线程范围内共享变量(ThreadLocal)

来源:互联网 发布:正在进行另一java安装 编辑:程序博客网 时间:2024/05/16 15:42

       线程范围内共享变量数据,是指在各自的线程范围内,访问各自线程内的数据,不会因为多个线程的同时操作,而导致线程内部的数据混乱。如图:

             

实现线程范围内变量数据共享的方式

第一种:

           如果每个线程执行的代码相同,可以使用同一个Runnable对象,这个Runnable对象中有那个共享数据。

示例一:

public class enjoyData {    //定义一个局部成员变量Map,用来存取每个线程中产生的数据。    private static Map<Thread, Integer> threadMapData = new HashMap<Thread, Integer>();            public static void main(String[] args) {          //共启动2个线程          for(int i=0;i<2;i++){              //启动一个线程                   new Thread(new Runnable(){                              @Override                       public void run() {                           int data = new Random().nextInt();  //产生随机数                         System.out.println(Thread.currentThread().getName()                                    + "产生的数据:" + data);                           //以当前线程为key值放入到map中,当取值时根据各自的线程取各自的数据                           threadMapData.put(Thread.currentThread(), data);                           new A().get();                           new B().get();                       }                            }).start();                     }      }            static class A{          public void get(){              int data = threadMapData.get(Thread.currentThread());              System.out.println("A 从 " + Thread.currentThread().getName()                       + " 读取到的数据 :" + data);          }      }            static class B{          public void get(){              int data = threadMapData.get(Thread.currentThread());                        System.out.println("B 从 " + Thread.currentThread().getName()                       + " 读取到的数据 :" + data);          }             }  }

第二种:

          如果每个线程执行的代码不同,这时候需要用不同的Runnable对象,有如下两种方式来实现这些Runnable对象之间的数据共享:

方法1:将需要共享的数据封装成一个对象,将该对象传给执行不同代码的Runnable对象。

 

方法2:将这些Runnable对象作为某一个类中的内部类,共享数据作为这个外部类中的成员变量,每个线程对共享数据的操作方法也分配给外部类,以便实现对共享数据进行的各个操作的互斥和通信,作为内部类的各个Runnable对象调用外部类的这些方法。

 

       上面两种方式的组合:将共享数据封装在另外一个对象中,每个线程对共享数据的操作方法也分配到那个对象身上去完成,对象作为这个外部类中的成员变量或方法中的局部变量,每个线程的Runnable对象作为外部类中的成员内部类或局部内部类。

总之,要同步互斥的几段代码最好是分别放在几个独立的方法中,这些方法再放在同一个类中,这样比较容易实现它们之间的同步互斥和通信。

示例:

public class enjoyVariableData {// 使用ThreadLocal实例化一个MyThreadScopeData类的成员对象private static ThreadLocal<MyThreadScopeData> Map = new ThreadLocal<MyThreadScopeData>();public static void main(String[] args) {for (int i = 0; i < 2; i++) {new Thread(new Runnable() {@Overridepublic void run() {// 产生随机数int data = new Random().nextInt();System.out.println(Thread.currentThread().getName()+ " 产生的随机数 :" + data);      //每一个线程都创建一个存放数据的MyThreadScopeData的实例对象                  MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();                    myData.setName("name" + data);                    myData.setAge(data);                    Map.set(myData);  new A().get();new B().get();}}).start();}}static class A {public void get() {// 获取当前线程存放的数据MyThreadScopeData myData = Map.get();System.out.println("A 从 " + Thread.currentThread().getName()+ " 读取到的数据: " + myData.getName() + ","+ "age:"+ myData.getAge());}}static class B {public void get() {// 获取当前线程存放的数据MyThreadScopeData myData = Map.get();System.out.println("B 从 " + Thread.currentThread().getName()+ " 读取到的数据: " + myData.getName() + ","+ "age:"+ myData.getAge());}}}publicclass MyThreadScopeData {// 实例化一个静态ThreadLocal对象Map。用于存储instanceprivate static ThreadLocal<MyThreadScopeData> map = new ThreadLocal<MyThreadScopeData>();public static  MyThreadScopeData getThreadInstance() {MyThreadScopeData instance = map.get();if (instance == null) { // 如果Singleton对象为null,就去new一个MyThreadScopeData()对象instance = new MyThreadScopeData();// 将新创建的MyThreadScopeData对象付给Singleton。map.set(instance);// 存储singleton}return instance;}private String name;private int age;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;}}

打印结果:


总结:

   ThreadLocal会为每一个线程维护一个和该线程绑定的变量的副本,从而隔离了多个线程的数据,保证每一个线程都拥有自己的变量副本。






1 0
原创粉丝点击