ThreadLocal可以很方便的实现线程范围内的共享变量,ThreadLocal类就相当于一个Map。下面具体看这个类如何使用:

  • 1-1 利用ThreadLocal实现线程范围内的共享变量

  
  1. import java.util.Hashtable; 
  2. import java.util.Map; 
  3. import java.util.Random; 
  4. /* 
  5.   每个线程拥有自己独立的数据 
  6.   一个ThreadLocal代表一个变量,故其中只能放一个数据。 
  7.  */ 
  8. public class ThreadLocalTest {//三个模块中的一个; 
  9.     private static ThreadLocal<Integer> x=new ThreadLocal<Integer>();//x变量名 
  10.     //ThreadLocal里边存放MyThreadScopeData数据 
  11.     private static ThreadLocal<MyThreadScopeData> MyThreadScopeData=new ThreadLocal<MyThreadScopeData>(); 
  12.     public static void main(String[] args) { 
  13.         for (int i = 0; i < 2; i++) { 
  14.             new Thread(new Runnable() { 
  15.                 @Override 
  16.                 public void run() { 
  17.                     int data=new Random().nextInt(); 
  18.                     System.out.println(Thread.currentThread().getName() 
  19.                             +"has put data :"+data); 
  20.                     x.set(data);//往当前线程中放数据,与当前线程相关的,不是全局的 
  21.                     MyThreadScopeData myData=new MyThreadScopeData();//new一个对象MyThreadScopeData() 
  22.                     myData.setName("name"+data);//往myData里边存放数据 
  23.                     myData.setAge(data); 
  24.                     MyThreadScopeData.set(myData);//存数据 
  25.                     new A().get(); 
  26.                     new B().get(); 
  27.                      
  28.                 } 
  29.             }){}.start(); 
  30.         } 
  31.     } 
  32.      
  33.     static class A{ 
  34.         public void get(){ 
  35.             int data=x.get();//取与当前线程有关的数据 
  36.             System.out.println("A from "+Thread.currentThread().getName() 
  37.                     +" get data :"+data); 
  38.             MyThreadScopeData myData=MyThreadScopeData.get();//取数据,包括name和age 
  39.             System.out.println("A from "+Thread.currentThread().getName() 
  40.                     +"getmyData :"+myData.getName()+","
  41.             myData.getAge()); 
  42.         } 
  43.     } 
  44.      
  45.     static class B{ 
  46.         public void get(){ 
  47.             int data=x.get(); 
  48.             System.out.println("B from "+Thread.currentThread().getName() 
  49.                     +" get data :"+data); 
  50.         } 
  51.     } 
  52.  
  53. class MyThreadScopeData{//打包,定义成一个实体 
  54.     private String name; 
  55.     private int age; 
  56.     public String getName() { 
  57.         return name; 
  58.     } 
  59.     public void setName(String name) { 
  60.         this.name = name; 
  61.     } 
  62.     public int getAge() { 
  63.         return age; 
  64.     } 
  65.     public void setAge(int age) { 
  66.         this.age = age; 
  67.     } 

程序运行的结果如下:

上面的代码的整体思路:创建一个对象——放数据——取数据。代码组织的相当的糟糕,有没有一种优雅的实现实现方面呢?看下面的代码.

  • 对代码1-1的改善,实现线程范围内的共享变量

 


  
  1. import java.util.HashMap; 
  2. import java.util.Map; 
  3. import java.util.Random; 
  4.  
  5. public class ThreadLocalTest { 
  6.     private static ThreadLocal<Integer> x = new ThreadLocal<Integer>(); 
  7.     private static ThreadLocal<MyThreadScopeData> myThreadScopeData = new ThreadLocal<MyThreadScopeData>(); 
  8.     public static void main(String[] args) { 
  9.         for(int i=0;i<2;i++){ 
  10.             new Thread(new Runnable(){ 
  11.                 @Override 
  12.                 public void run() { 
  13.                     int data = new Random().nextInt(); 
  14.                     System.out.println(Thread.currentThread().getName()  
  15.                             + " has put data :" + data); 
  16.                     x.set(data); 
  17.                     //得到与本线程有关的实力对象,在设置值 
  18.                     MyThreadScopeData.getThreadInstance().setName("name" + data); 
  19.                     MyThreadScopeData.getThreadInstance().setAge(data); 
  20.                     new A().get(); 
  21.                     new B().get(); 
  22.                 } 
  23.             }).start(); 
  24.         } 
  25.     } 
  26.      
  27.     static class A{ 
  28.         public void get(){ 
  29.             int data = x.get(); 
  30.             System.out.println("A from " + Thread.currentThread().getName()  
  31.                     + " get data :" + data); 
  32.             MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();//得到与本线程有关的实例对象,在设置值 
  33.             System.out.println("A from " + Thread.currentThread().getName()  
  34.                     + " getMyData: " + myData.getName() + "," + 
  35.                     myData.getAge()); 
  36.         } 
  37.     } 
  38.      
  39.     static class B{ 
  40.         public void get(){ 
  41.             int data = x.get();          
  42.             System.out.println("B from " + Thread.currentThread().getName()  
  43.                     + " get data :" + data); 
  44.             MyThreadScopeData myData = MyThreadScopeData.getThreadInstance();//得到与本线程有关的实例对象,在设置值 
  45.             System.out.println("B from " + Thread.currentThread().getName()  
  46.                     + " getMyData: " + myData.getName() + "," + 
  47.                     myData.getAge());            
  48.         }        
  49.     } 
  50.  
  51. class MyThreadScopeData{//将实体转化成单例 
  52.     private MyThreadScopeData(){}//第一件事:构造方法私有化,让其它的没法创建它的实例对象 
  53.     public static /*synchronized*/ MyThreadScopeData getThreadInstance(){ 
  54.         //利用静态方法,得到实例对象,synchronized时,在饥汉模式下 
  55.         MyThreadScopeData instance = map.get(); 
  56.         if(instance == null){//饥汉模式,只有第一次时创建(需要的时候创建),以后直接饭回instance 
  57.             instance = new MyThreadScopeData();//注意饥汉模式下,可能第一个线程来 
  58.             //检查instance == null,就去创建(赋值),还没有返回的时候,CPU切换到第二个线程,第二个线程来检查, 
  59.             //创建(赋值),那么可能就出现,第二次赋值覆盖第一次赋值,所以要互斥synchronized 
  60.             map.set(instance);//将值存起来 
  61.         } 
  62.         return instance;//返回实例对象 
  63.     } 
  64.     //private static MyThreadScopeData instance = new MyThreadScopeData();//饱汉模式 
  65.     //private static MyThreadScopeData instance = null;//饥汉模式 
  66.     //装线程范围内的共享变量 
  67.     private static ThreadLocal<MyThreadScopeData> map = new ThreadLocal<MyThreadScopeData>(); 
  68.      
  69.     private String name; 
  70.     private int age; 
  71.     public String getName() { 
  72.         return name; 
  73.     } 
  74.     public void setName(String name) { 
  75.         this.name = name; 
  76.     } 
  77.     public int getAge() { 
  78.         return age; 
  79.     } 
  80.     public void setAge(int age) { 
  81.         this.age = age; 
  82.     } 

程序运行的结果:

每一请求(每一个线程),有一个容器对象,这个容器对象存放与这个请求有关的所有数据,struts2中会有这种思想。