ThreadLocal-分析-总结

系统 1553 0

原文地址: http://www.iteye.com/topic/777716

ThreadLocal<T>类在Spring,Hibernate等框架中起到了很大的作用,对于其工作原理,很多网上的文章分析的不够彻底,甚至有些误解。

 

首先,为了解释ThreadLocal类的工作原理,必须同时介绍与其工作甚密的其他几个类(内部类)

1.ThreadLocalMap

2.Thread

ThreadLocal-分析-总结

可能有人会觉得Thread与ThreadLocal有什么关系,其实真正的奥秘就在Thread类中的一行:

 

Java代码 复制代码   收藏代码
  1. ThreadLocal.ThreadLocalMap threadLocals =  null ;  

 其中ThreadLocalMap的定义是在ThreadLocal类中,真正的引用却是在Thread类中

 

那么ThreadLocalMap究竟是什么呢?

 

可以看到这个类应该是一个Map,JDK的解释是

 

 写道
ThreadLocalMap is a customized hash map suitable only for maintaining thread local values

 

 

接下来的重点是ThreadLocalMap中用于存储数据的entry

 

Java代码 复制代码   收藏代码
  1. static   class  Entry  extends  WeakReference<ThreadLocal> {   
  2.              /** The value associated with this ThreadLocal. */   
  3.             Object value;   
  4.   
  5.             Entry(ThreadLocal k, Object v) {   
  6.                  super (k);   
  7.                 value = v;   
  8.             }   
  9.         }  

 

 从中我们可以发现 这个Map的key是ThreadLocal变量,value为用户的值,并不是网上大多数的列子key是线程的名字或者标识

 

到这里,我们就可以理解ThreadLocal究竟是如何工作的了

 

1.Thread类中有一个成员变量叫做ThreadLocalMap,它是一个Map,他的Key是ThreadLocal类

2 .每个线程拥有自己的申明为ThreadLocal类型的变量,所以这个类的名字叫'ThreadLocal':线程自己的(变量)

3.此变量生命周期是由该线程决定的,开始于第一次初始(get或者set方法)

4.由ThreadLocal的工作原理决定了: 每个线程独自拥有一个变量,并非共享或者拷贝

 

Java代码 复制代码   收藏代码
  1. /**  
  2.  * @author mxdba  
  3.  *  
  4.  */   
  5. public   class  ThreadLocalSample {   
  6.   
  7.      public   static   void  main(String[] args) {   
  8.         ThreadTest test1 =  new  ThreadTest( 10 );   
  9.         ThreadTest test2 =  new  ThreadTest( 20 );   
  10.         test1.start();   
  11.         test2.start();   
  12.     }   
  13.   
  14. }   
  15.   
  16. /**  
  17.  * 此线程有两个ThreadLocal变量,但是由于ThreadLocal是延迟初始的,  
  18.  * 所以在debug时可以看到线程名为“线程20”的线程的ThreadLocalMap中没有thLcal2这个entry  
  19.  * @author mxdba  
  20.  *   
  21.  */   
  22. class  ThreadTest  extends  Thread {   
  23.        
  24.      public   static  ThreadLocal<Integer> thLocal =  new  ThreadLocal<Integer>();   
  25.      public   static  ThreadLocal<String> thLocal2 =  new  ThreadLocal<String>();   
  26.        
  27.      public  Integer num;   
  28.        
  29.        
  30.        
  31.      public  ThreadTest(Integer num) {   
  32.          super ( "线程"  + num);   
  33.          this .num = num;   
  34.     }   
  35.   
  36.      @Override   
  37.      public   void  run() {   
  38.         Integer n = thLocal.get();   
  39.          if (num !=  20 ) {   
  40.             String s = thLocal2.get();   
  41.         }   
  42.                
  43.          if (n ==  null ) {   
  44.             thLocal.set(num);   
  45.         }   
  46.         System.out.println(thLocal.get());   
  47.     }   
  48.        
  49. }  

 

 

接下来分析一下源码,就更加清楚了

 

关键方法代码 复制代码   收藏代码
  1. /**   
  2.  * 关键方法,返回当前Thread的ThreadLocalMap   
  3.  * [[[每个Thread返回各自的ThreadLocalMap,所以各个线程中的ThreadLocal均为独立的]]]   
  4.  */   
  5. ThreadLocalMap getMap(Thread t) {   
  6.         return t.threadLocals;   
  7.     }  

 

 

 

 

Threadlocal的get方法代码 复制代码   收藏代码
  1. public T get() {   
  2.         Thread t = Thread.currentThread();   
  3.         /**   
  4.          * 得到当前线程的ThreadLocalMap   
  5.          */   
  6.         ThreadLocalMap map = getMap(t);   
  7.         if (map != null) {   
  8.             /**   
  9.              * 在此线程的ThreadLocalMap中查找key为当前ThreadLocal对象的entry   
  10.              */   
  11.             ThreadLocalMap.Entry e = map.getEntry(this);   
  12.             if (e != null)   
  13.                 return (T)e.value;   
  14.         }   
  15.         return setInitialValue();   
  16.     }  

 

 

 

 

初始化方法代码 复制代码   收藏代码
  1. private T setInitialValue() {   
  2.         /**   
  3.          * 默认返回null,这个方法为protected可以继承   
  4.          */   
  5.         T value = initialValue();   
  6.         Thread t = Thread.currentThread();   
  7.         ThreadLocalMap map = getMap(t);   
  8.         if (map != null)   
  9.             map.set(this, value);   
  10.         else   
  11.             /**   
  12.              * 初次创建   
  13.              */   
  14.             createMap(t, value);   
  15.         return value;   
  16.     }  

 

 

 

Java代码 复制代码   收藏代码
  1. /**  
  2.  * 给当前thread初始ThreadlocalMap  
  3.  */   
  4. void  createMap(Thread t, T firstValue) {   
  5.         t.threadLocals =  new  ThreadLocalMap( this , firstValue);   
  6.     }  

 

 

 

通过上边的分析,我们发现,ThreadLocal类的使用虽然是用来解决多线程的问题的,但是还是有很明显的针对性

1. 最明显的,ThreadLoacl变量的活动范围为某线程,并且我的理解是该线程“专有的,独自霸占”,对该变量的所有操作均有该线程完成! 也就是说,ThreadLocal不是用来解决共享,竞争问题的。典型的应用莫过于Spring,Hibernate等框架中对于多线程的处理了

 

Java代码 复制代码   收藏代码
  1. private   static   final  ThreadLocal threadSession =  new  ThreadLocal();     
  2.      
  3. public   static  Session getSession()  throws  InfrastructureException {     
  4.     Session s = (Session) threadSession.get();     
  5.      try  {     
  6.          if  (s ==  null ) {     
  7.             s = getSessionFactory().openSession();     
  8.             threadSession.set(s);     
  9.         }     
  10.     }  catch  (HibernateException ex) {     
  11.          throw   new  InfrastructureException(ex);     
  12.     }     
  13.      return  s;     
  14. }    

 这段代码,每个线程有自己的ThreadLocalMap,每个ThreadLocalMap中根据需要初始加载threadSession,这样的好处就是介于singleton与prototype之间,应用singleton无法解决线程,应用prototype开销又太大,有了ThreadLocal之后就好了,对于需要线程“霸占”的变量用ThreadLocal,而该类实例的方法均可以共享。

 

2.关于内存泄漏:

虽然ThreadLocalMap已经使用了weakReference,但是还是建议能够显示的使用remove方法。

  • ThreadLocal-分析-总结
  • 大小: 9.9 KB
  • ThreadLocal-分析-总结
  • 大小: 13.9 KB

ThreadLocal-分析-总结


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论