天天看點

Java中如何實作單個線程範圍内的資料共享

單個線程範圍内的資料共享,就是確定目前的線程在執行的過程中,各個子產品所引用的資料是一份,且所引用的資料不會因為其他線程的操作而變化。

以下是一段沒有達到線程内資料共享的代碼(參考自傳智播客視訊)

public class ThreadScopeShareData
{
    //用于存放随機産生的資料
    static int data = 0; 
    public static void main(String[] args)
    {
        //線程1
        new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                data = new Random().nextInt(1000);
                System.out.println(Thread.currentThread().getName() 
                        + "has put data:" + data);
                //使用A對象輸出資料
                new A().getData();
                //使用B對象輸出資料
                new B().getData();
            }
        }).start();
        
        //線程2
        new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                data = new Random().nextInt(1000);
                System.out.println(Thread.currentThread().getName() 
                        + "has put data:" + data);
                //使用A對象輸出資料
                new A().getData();
                //使用B對象輸出資料
                new B().getData();
            }
        }).start();
    }
}

class A
{
    public void getData()
    {
        System.out.println("A :" + Thread.currentThread().getName()
                + ": get data value:" + ThreadScopeShareData.data);
    }
}

class B
{
    public void getData()
    {
        System.out.println("B :" + Thread.currentThread().getName()
                + ": get data value:" + ThreadScopeShareData.data);
    }
}
           

控制台輸出:

Java中如何實作單個線程範圍内的資料共享

根據控制台的結果,可以看出,由于定義了static的變量存儲資料,那麼當線程2更改了data資料後,線程1中 A子產品和B子產品取出的和當初線程1放入的不是一個值,如何解決這個問題呢?見如下代碼:

一、使用全局的map變量實作

public class ThreadScopeShareData
{
    //用于存放随機産生的資料
    //static int data = 0; 
    /*
     * 使用map類型的變量取代int類型的變量
     */
    static Map<Thread, Integer> map = new HashMap<Thread, Integer>();
    public static void main(String[] args)
    {
        //線程1
        new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                //data = new Random().nextInt(1000);
                int data = new Random().nextInt(1000);
                //用目前線程作為key,将目前線程産生的随機數,存入map中
                map.put(Thread.currentThread(), data);
                System.out.println(Thread.currentThread().getName() 
                        + " has put data:" + data);
                //使用A對象輸出資料
                new A().getData();
                //使用B對象輸出資料
                new B().getData();
            }
        }).start();
        
        //線程2
        new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                int data = new Random().nextInt(1000);
                //用目前線程作為key,将目前線程産生的随機數,存入map中
                map.put(Thread.currentThread(), data);
                System.out.println(Thread.currentThread().getName() 
                        + " has put data:" + data);
                //使用A對象輸出資料
                new A().getData();
                //使用B對象輸出資料
                new B().getData();
            }
        }).start();
    }
}

class A
{
    public void getData()
    {
        //使用目前線程作為map的key去取出map中對應的value
        System.out.println("A :" + Thread.currentThread().getName()
                + ": get data value:" 
                + ThreadScopeShareData.map.get(Thread.currentThread()));
    }
}

class B
{
    public void getData()
    {
      //使用目前線程作為map的key去取出map中對應的value
        System.out.println("B :" + Thread.currentThread().getName()
                + ": get data value:"
                + ThreadScopeShareData.map.get(Thread.currentThread()));
    }
}
           

二、使用ThreadLocal類,實作單個線程範圍内 單個變量的資料共享

public class ThreadScopeShareData
{
    /*
     * 使用ThreadLocal
     */
    static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>();
    public static void main(String[] args)
    {
        //線程1
        new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                int data = new Random().nextInt(1000);
                //将目前線程産生的随機數,存入threadLocal中
                threadLocal.set(data);
                System.out.println(Thread.currentThread().getName() 
                        + " has put data:" + data);
                //使用A對象輸出資料
                new A().getData();
                //使用B對象輸出資料
                new B().getData();
            }
        }).start();
        
        //線程2
        new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                int data = new Random().nextInt(1000);
                //将目前線程産生的随機數,存入threadLocal中
                threadLocal.set(data);
                System.out.println(Thread.currentThread().getName() 
                        + " has put data:" + data);
                //使用A對象輸出資料
                new A().getData();
                //使用B對象輸出資料
                new B().getData();
            }
        }).start();
    }
}

class A
{
    public void getData()
    {
        //從threadLocal中取出value
        System.out.println("A :" + Thread.currentThread().getName()
                + ": get data value:" 
                + ThreadScopeShareData.threadLocal.get());
    }
}

class B
{
    public void getData()
    {
        //從threadLocal中取出value
        System.out.println("B :" + Thread.currentThread().getName()
                + ": get data value:"
                + ThreadScopeShareData.threadLocal.get());
    }
}
           

三、使用ThreadLocal實作 單個線程内 多個變量的資料共享

實作多個資料的共享可以使用Map去存放資料,這裡就不說了 就是把ThreadLocal中的Integer替換成Map即可,主要貼一下使用對象存儲多個變量的代碼實作

①建立一個用于存放共享資料的類

/**
 * 存放共享資料的對象
 * @author ***
 *
 */
class ShareDataObj
{
    /**
     * threadLocal
     */
    private static ThreadLocal<ShareDataObj> threadLocal = 
        new ThreadLocal<ShareDataObj>();
    
    private ShareDataObj()
    {
    }
    
    /**
     * 傳回從ThreadLocal中取出目前線程的ShareDataObj對象
     * @return
     */
    public static ShareDataObj getInstance4currentThread()
    {
        //從threadLocal變量中取出目前線程的ShareDataObj對象
        ShareDataObj dataObj = threadLocal.get();
        if(dataObj == null)
        {
            //1、建立一個新的對象
            dataObj = new ShareDataObj();
            //2、将建立的對象放入ShareDataObj對象中
            threadLocal.set(dataObj);
        }
        
        return dataObj;
    }
    
    //data1
    private int data1;
    //data2
    private String data2;

    public int getData1()
    {
        return data1;
    }

    public void setData1(int data1)
    {
        this.data1 = data1;
    }

    public String getData2()
    {
        return data2;
    }

    public void setData2(String data2)
    {
        this.data2 = data2;
    }
}
           

②操作共享資料

public class ThreadScopeShareData
{
    public static void main(String[] args)
    {
        //線程1
        new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                int data = new Random().nextInt(1000);
                //将目前線程産生的随機數,放入資料共享對象中
                ShareDataObj.getInstance4currentThread().setData1(data);
                ShareDataObj.getInstance4currentThread().setData2("str-" + data);
                
                System.out.println(Thread.currentThread().getName() 
                        + " has put data:" + data);
                //使用A對象輸出資料
                new A().getData();
                //使用B對象輸出資料
                new B().getData();
            }
        }).start();
        
        //線程2
        new Thread(new Runnable()
        {
            @Override
            public void run()
            {
                int data = new Random().nextInt(1000);
                //将目前線程産生的随機數,放入資料共享對象中
                ShareDataObj.getInstance4currentThread().setData1(data);
                ShareDataObj.getInstance4currentThread().setData2("str-" + data);
                
                System.out.println(Thread.currentThread().getName() 
                        + " has put data:" + data);
                //使用A對象輸出資料
                new A().getData();
                //使用B對象輸出資料
                new B().getData();
            }
        }).start();
    }
}

class A
{
    public void getData()
    {
        //從ShareDataObj中取出目前線程的資料共享對象
        System.out.println("A :" + Thread.currentThread().getName()
                + ": get data1:" 
                + ShareDataObj.getInstance4currentThread().getData1()
                + ", get data2:"
                + ShareDataObj.getInstance4currentThread().getData2());
    }
}

class B
{
    public void getData()
    {
        //從ShareDataObj中取出目前線程的資料共享對象
        System.out.println("B :" + Thread.currentThread().getName()
                + ": get data1:" 
                + ShareDataObj.getInstance4currentThread().getData1()
                + ", get data2:"
                + ShareDataObj.getInstance4currentThread().getData2());
    }
}