【Java多线程与并发库】6.ThreadLocal类及应用技巧

来源:互联网 发布:linux jdk下载 64位 编辑:程序博客网 时间:2024/05/29 03:30
之前我们了解了实现线程范围内数据共享的机制,接下来我们
可以使用JDK5提供的ThreadLocal类,来实现线程范围内数据共享。

ThreadLocal类其实就类似于我们上一次创建的Map。

我们创建一个测试类,来使用ThreadLocal类实现线程范围内数据共享:
我们的类A和类B每次都从线程中获取data值打印,为了保证每次打印的数据是该线程的数据,

类A和类B的数据都从ThreadLocal中获取。

  1. package cn.edu.hpu.test;  
  2.   
  3. import java.util.Random;  
  4.   
  5. public class ThreadTest7 {  
  6.       
  7.     private static Random dandom=new Random();  
  8.     private static ThreadLocal<Integer> x=new ThreadLocal<Integer>();  
  9.   
  10.     public static void main(String[] args) {  
  11.         for(int i=0;i<2;i++){  
  12.             new Thread(new Runnable(){  
  13.                 public void run() {  
  14.                     int data=dandom.nextInt();  
  15.                     System.out.println(Thread.currentThread().getName()  
  16.                             +"放入数据:"+data);  
  17.                     x.set(data);  
  18.                     new A().get();  
  19.                     new B().get();  
  20.                 }  
  21.                   
  22.             }).start();  
  23.         }  
  24.     }  
  25.       
  26.     static class A{  
  27.         public void get(){  
  28.             System.out.println("A 从"+Thread.currentThread().getName()  
  29.                     +"中取的数据:"+x.get());  
  30.         }  
  31.     }  
  32.       
  33.     static class B{  
  34.         public void get(){  
  35.             System.out.println("B 从"+Thread.currentThread().getName()  
  36.                     +"中取的数据:"+x.get());  
  37.         }  
  38.     }  
  39. }  
结果:



实现了每个线程中的数据共享在每个线程自己的范围内。线程之间的数据不会混杂在一起。

如果有N个变量需要做到线程范围内数据共享,应该如何做到?
一个ThreadLocal只能放一个变量,我们可以使用多个ThreadLocal来实现,
如果共享的数据量过大,我们就把这些数据放在一个对象中,然后在ThreadLocal中
存储这一个对象。

  1. package cn.edu.hpu.test;  
  2.   
  3. import java.util.Random;  
  4.   
  5. public class ThreadTest7 {  
  6.       
  7.     private static Random dandom=new Random();  
  8.     private static ThreadLocal<MyThreadScopeData> MyThreadScopeData=new ThreadLocal<MyThreadScopeData>();  
  9.   
  10.     public static void main(String[] args) {  
  11.         for(int i=0;i<2;i++){  
  12.             new Thread(new Runnable(){  
  13.                 public void run() {  
  14.                     int data=dandom.nextInt();  
  15.                     System.out.println(Thread.currentThread().getName()  
  16.                             +"放入数据:"+data);  
  17.                     MyThreadScopeData ScopeData=new MyThreadScopeData();  
  18.                     ScopeData.setName("name"+data);  
  19.                     ScopeData.setAge(data);  
  20.                     MyThreadScopeData.set(ScopeData);  
  21.                     new A().get();  
  22.                     new B().get();  
  23.                 }  
  24.                   
  25.             }).start();  
  26.         }  
  27.     }  
  28.       
  29.     static class A{  
  30.         public void get(){  
  31.             System.out.println("A 从"+Thread.currentThread().getName()  
  32.                     +"中取的数据:"+MyThreadScopeData.get().getName()  
  33.                     +MyThreadScopeData.get().getAge());  
  34.         }  
  35.     }  
  36.       
  37.     static class B{  
  38.         public void get(){  
  39.             System.out.println("A 从"+Thread.currentThread().getName()  
  40.                     +"中取的数据:"+MyThreadScopeData.get().getName()  
  41.                     +MyThreadScopeData.get().getAge());  
  42.         }  
  43.     }  
  44. }  
  45.   
  46. class MyThreadScopeData{  
  47.     private String name;  
  48.     private int age;  
  49.     public String getName() {  
  50.         return name;  
  51.     }  
  52.     public void setName(String name) {  
  53.         this.name = name;  
  54.     }  
  55.     public int getAge() {  
  56.         return age;  
  57.     }  
  58.     public void setAge(int age) {  
  59.         this.age = age;  
  60.     }  
  61. }  

结果:


这样就可以在线程范围内共享N中数据了。

上面的设计其实不够好,但是要设计更加优雅一点,不要看到我们使用ThreadLocal的痕迹:

  1. package cn.edu.hpu.test;  
  2.   
  3. import java.util.Random;  
  4.   
  5. public class ThreadTest7 {  
  6.       
  7.     private static Random dandom=new Random();  
  8.     public static void main(String[] args) {  
  9.         for(int i=0;i<2;i++){  
  10.             new Thread(new Runnable(){  
  11.                 public void run() {  
  12.                     int data=dandom.nextInt();  
  13.                     System.out.println(Thread.currentThread().getName()  
  14.                             +"放入数据:"+data);  
  15.   
  16.                     MyThreadScopeData.getThreadInstance().setName("name"+data);  
  17.                     MyThreadScopeData.getThreadInstance().setAge(data);  
  18.                     new A().get();  
  19.                     new B().get();  
  20.                 }  
  21.                   
  22.             }).start();  
  23.         }  
  24.     }  
  25.       
  26.     static class A{  
  27.         public void get(){  
  28.             System.out.println("A 从"+Thread.currentThread().getName()  
  29.                     +"中取的数据:"+MyThreadScopeData.getThreadInstance().getName()  
  30.                     +MyThreadScopeData.getThreadInstance().getAge());  
  31.         }  
  32.     }  
  33.       
  34.     static class B{  
  35.         public void get(){  
  36.             System.out.println("A 从"+Thread.currentThread().getName()  
  37.                     +"中取的数据:"+MyThreadScopeData.getThreadInstance().getName()  
  38.                     +MyThreadScopeData.getThreadInstance().getAge());  
  39.         }  
  40.     }  
  41. }  
  42.   
  43. class MyThreadScopeData{  
  44.       
  45.     private MyThreadScopeData(){}  
  46.     public static MyThreadScopeData getThreadInstance(){  
  47.         MyThreadScopeData instance=map.get();  
  48.         if(instance==null){  
  49.             instance=new MyThreadScopeData();  
  50.             map.set(instance);  
  51.         }  
  52.         return instance;  
  53.     }  
  54.     private static ThreadLocal<MyThreadScopeData> map =new ThreadLocal<MyThreadScopeData>();  
  55.       
  56.     private String name;  
  57.     private int age;  
  58.     public String getName() {  
  59.         return name;  
  60.     }  
  61.     public void setName(String name) {  
  62.         this.name = name;  
  63.     }  
  64.     public int getAge() {  
  65.         return age;  
  66.     }  
  67.     public void setAge(int age) {  
  68.         this.age = age;  
  69.     }  
  70. }  

这里,我们调用MyThreadScopeData的getThreadInstance方法,就可以取得
与当前线程相关的实例对象。

虽然线程结束后也可以自动释放相关的ThreadLocal变量,但是为了优化内存,
我们的ThreadLocal要在线程结束的时候注销,可以调用ThreadLocal.clear()方法。

出处:http://blog.csdn.net/acmman/article/details/52794523

0 0
原创粉丝点击