多线程05-线程范围内共享变量

1.问题引入

     多个业务模块针对同一个static变量的操作 要保证在不同线程中 各模块操作的是自身对应的变量对象

例如: 



package org.lkl.thead;



import java.util.Random;



/**

 * 线程共享数据

 * Function : 

 * @author : Liaokailin

 * CreateDate : 2014-6-12

 * version : 1.0

 */

public class ThreadShareData {



    private static  int data = 0 ;

    

    public static void main(String[] args) {

      for(int i = 0 ;i<2 ;i++){

        new Thread(new Runnable(){



            @Override

            public void run() {

                data = new Random().nextInt();

                System.out.println(Thread.currentThread().getName()+ " put random data:"+data);

                new A().get() ;

                new B().get() ;

            }

            

        }).start() ;

      }

        

    }

    

    static class A {

        public int get(){

            System.out.println("A from " + Thread.currentThread().getName() 

                    + " get data :" + data);

            return data ;

        }

    }

    

    static class B{

        public int get(){

            System.out.println("B from " + Thread.currentThread().getName() 

                    + " get data :" + data);

            return data ;

        }

    }

}

 

   模块A ,B都需要访问static的变量data   在线程0中会随机生成一个data值 假设为10  那么此时模块A和模块B在线程0中得到的data的值为10 ;在线程1中 假设会为data赋值为20 那么在当前线程下

模块A和模块B得到data的值应该为20 

       看程序执行的结果: 

       

Thread-0 put random data:-1344602819

Thread-1 put random data:-1842611697

A from Thread-1 get data :-1842611697

A from Thread-0 get data :-1842611697

B from Thread-1 get data :-1842611697

B from Thread-0 get data :-1842611697

 

     在线程0中执行模块A和模块B的方法去获取data的值 但是在获取之前  线程1就将data的值给修改为-1842611697 导致线程0中的模块A和模块B获取了错误的数据.  

 

2.解决问题

       那么如何得到正确的效果呢? 

       可是将data数据和当前允许的线程绑定在一块,在模块A和模块B去获取数据data的时候 是通过当前所属的线程去取得data的结果就行了。

       声明一个Map集合 集合的Key为Thread 存储当前所属线程 Value 保存data的值,代码如下: 

package org.lkl.thead.sharedata;



import java.util.HashMap;

import java.util.Map;

import java.util.Random;



/**

 * 线程共享数据

 * Function : 

 * @author : Liaokailin

 * CreateDate : 2014-6-12

 * version : 1.0

 */

public class ThreadShareData {



    private static  int data = 0 ;

    private static Map<Thread,Integer> threadData = new HashMap<Thread, Integer>() ;

    

    public static void main(String[] args) {

      for(int i = 0 ;i<2 ;i++){

        new Thread(new Runnable(){



            @Override

            public  void run() {

                synchronized (ThreadShareData.class) {  //保证下面的代码都执行完才允许其他线程进入

                    data = new Random().nextInt();

                    threadData.put(Thread.currentThread(), data) ; //将数据绑定到带当前线程

                    System.out.println(Thread.currentThread().getName()+ " put random data:"+data);

                    new A().get() ;

                    new B().get() ;

                }

            }

            

        }).start() ;

      }

        

    }

    

    static class A {

        public int get(){

            //取数据都从当前线程中取得 

            int d = threadData.get(Thread.currentThread()) ;

            System.out.println("A from " + Thread.currentThread().getName() 

                    + " get data :" + d);

            return data ;

        }

    }

    

    static class B{

        public int get(){

            //取数据都从当前线程中取得 

            int d  = threadData.get(Thread.currentThread()) ;

            System.out.println("B from " + Thread.currentThread().getName() 

                    + " get data :" + d);

            return data ;

        }

    }

}

 

        程序执行的结果: 

Thread-0 put random data:-1842492021

A from Thread-0 get data :-1842492021

B from Thread-0 get data :-1842492021

Thread-1 put random data:-1886142929

A from Thread-1 get data :-1886142929

B from Thread-1 get data :-1886142929

 

 

3 问题的拓展

     将数据与当前线程相挂钩的话 那么显然是可以利用ThreadLocal这个类  那么改造上面的代码得到下面的代码:

package org.lkl.thead.sharedata;



import java.util.Random;



/**

 * 线程共享数据

 * Function : 

 * @author : Liaokailin

 * CreateDate : 2014-6-12

 * version : 1.0

 */

public class ThreadShareData {



    private static  int data = 0 ;

    /**

     * ThreadLocal 类似于map集合 只是集合的key是当前正在运行的线程 * 通过ThreadLocal可以将变量(或者是变量的容器)与当前线程相绑定. */

    private static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>() ;

    

    

    public static void main(String[] args) {

      for(int i = 0 ;i<2 ;i++){

        new Thread(new Runnable(){



            @Override

            public  void run() {

                synchronized (ThreadShareData.class) {  //保证下面的代码都执行完才允许其他线程进入

                    data = new Random().nextInt();

                    threadLocal.set(data) ; //将数据绑定到带当前线程

                    System.out.println(Thread.currentThread().getName()+ " put random data:"+data);

                    new A().get() ;

                    new B().get() ;

                }

            }

            

        }).start() ;

      }

        

    }

    

    static class A {

        public int get(){

            //取数据都从当前线程中取得 

            int d = threadLocal.get() ;

            System.out.println("A from " + Thread.currentThread().getName() 

                    + " get data :" + d);

            return data ;

        }

    }

    

    static class B{

        public int get(){

            //取数据都从当前线程中取得 

            int d = threadLocal.get() ;

            System.out.println("B from " + Thread.currentThread().getName() 

                    + " get data :" + d);

            return data ;

        }

    }

}

 

        代码执行完以后会得到同样的效果。

        接下来还有一个问题  上面一直讨论的是线程间共享一个变量 那么如果是多个变量呢? 

        要直接ThreadLocal每次只能是一个变量和当前线程挂钩 如果有多个变量要和当前线程挂钩的话 就得生命多个ThreadLocal对象 这样子做很显然是不合理的。那如何处理呢? 

        由于ThreadLocal可以并且只能和一个变量挂钩,那么我们可以将这个变量设置为一个变量的容器,容器中可以存在多个变量,这也就是将需要和当前线程绑定的变量封装到一个实体类中

package org.lkl.thead.sharedata;



import java.util.Random;



/**

 * 线程共享数据

 * Function : 

 * @author : Liaokailin

 * CreateDate : 2014-6-12

 * version : 1.0

 */

public class ThreadShareData {



    private static  int data = 0 ;

    

    public static void main(String[] args) {

      for(int i = 0 ;i<2 ;i++){

        new Thread(new Runnable(){



            @Override

            public  void run() {

                synchronized (ThreadShareData.class) {  //保证下面的代码都执行完才允许其他线程进入

                    data = new Random().nextInt();

                    VariableContainer.getThreadInstance().setAge(data) ;

                    VariableContainer.getThreadInstance().setName("liaokailin-"+data) ; 

                    System.out.println(Thread.currentThread().getName()+ " Put  VariableContainer:"+VariableContainer.getThreadInstance().toString());

                    new A().get() ;

                    new B().get() ;

                }

            }

            

        }).start() ;

      }

        

    }

    

    static class A {

        public int get(){

            //取数据都从当前线程中取得 

            System.out.println("A from " + Thread.currentThread().getName() 

                    + " get data :" + VariableContainer.getThreadInstance().toString());

            return data ;

        }

    }

    

    static class B{

        public int get(){

            //取数据都从当前线程中取得 

             

            System.out.println("B from " + Thread.currentThread().getName() 

                    + " get data :" + VariableContainer.getThreadInstance().toString());

            return data ;

        }

    }

    

}





/**

 * 变量容器

 */

class VariableContainer{

    private String name ;

    private int age ;

    private static  ThreadLocal<VariableContainer> threadLocal = new ThreadLocal<VariableContainer>() ;

    /**

     * 获取当前线程中绑定的变量容器   外部可以往容器中设值

     */

    public static VariableContainer  getThreadInstance(){

        VariableContainer container = threadLocal.get() ;

        if(container==null){

            container = new VariableContainer() ;

            threadLocal.set(container) ;

        }

        return container ;

        

    }

    

    public String getName() {

        return name;

    }

    public void setName(String name) {

        this.name = name;

    }

    public int getAge() {

        return age;

    }

    public void setAge(int age) {

        this.age = age;

    }



    @Override

    public String toString() {

        return "VariableContainer [name=" + name + ", age=" + age + "]";

    }

    

    

    

}

 

      执行结果: 

Thread-0 Put  VariableContainer:VariableContainer [name=liaokailin--2103275506, age=-2103275506]

A from Thread-0 get data :VariableContainer [name=liaokailin--2103275506, age=-2103275506]

B from Thread-0 get data :VariableContainer [name=liaokailin--2103275506, age=-2103275506]

Thread-1 Put  VariableContainer:VariableContainer [name=liaokailin-816504398, age=816504398]

A from Thread-1 get data :VariableContainer [name=liaokailin-816504398, age=816504398]

B from Thread-1 get data :VariableContainer [name=liaokailin-816504398, age=816504398]

 

 

 

 

 

 

 

 

你可能感兴趣的:(多线程)