`

ThreadLocal<T>总结补充

 
阅读更多


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

 

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

 

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

1.ThreadLocalMap

2.Thread

可能有人会觉得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方法。

 

 

附上PDF 供大家研究.....

 

分享到:
评论

相关推荐

    tls_src.zip_TLS

    `ThreadLocal&lt;T&gt;`提供了一个容器,用于存储类型为T的线程局部变量。创建`ThreadLocal&lt;T&gt;`实例时,会为每个线程分配一个独立的T类型的实例。这样,在多线程环境下,每个线程可以安全地使用自己的数据,而无需担心与...

    使用Java ThreadLocal.docx

    private ThreadLocal&lt;String&gt; myThreadLocal = new ThreadLocal&lt;&gt;(); ``` 这里的`&lt;String&gt;`是可选的,用于指定ThreadLocal变量所存储的值的类型。如果不指定泛型,那么`get()`和`set()`方法将返回或接收Object类型...

    ThreadLocal应用示例及理解

    ThreadLocal&lt;String&gt; threadLocal = new ThreadLocal&lt;&gt;(); ``` ### 设置和获取值 在ThreadLocal中,`set()`方法用于设置当前线程的ThreadLocal变量值,`get()`方法用于获取当前线程的ThreadLocal变量值。 ```java...

    ThreadLocal

    - 创建ThreadLocal实例:`ThreadLocal&lt;T&gt; threadLocal = new ThreadLocal&lt;T&gt;()` - 设置线程局部值:`threadLocal.set(value)` - 获取线程局部值:`T value = threadLocal.get()` - 移除线程局部值:`threadLocal...

    中小公司人事管理系统

    private static final ThreadLocal&lt;Session&gt; sessionThread=new ThreadLocal&lt;Session&gt;(); private static final ThreadLocal&lt;Transaction&gt; transactionThread=new ThreadLocal&lt;Transaction&gt;(); private static ...

    threadlocal.rar

    ThreadLocal&lt;Integer&gt; parentThreadLocal = new ThreadLocal&lt;&gt;(); ChildThread childThread = new ChildThread(parentThreadLocal); childThread.start(); ``` 2. **使用共享数据结构**: 父线程可以将ThreadLocal...

    c# 5.0语法介绍

    `ThreadLocal&lt;T&gt;`类在C# 5.0中引入,用于创建线程局部变量。这意味着每个线程都有自己的变量副本,互不影响。 例如: ```csharp ThreadLocal&lt;int&gt; threadCount = new ThreadLocal&lt;int&gt;(() =&gt; Environment....

    入研究java.lang.ThreadLocal类.docx

    ThreadLocal&lt;String&gt; threadLocal = new ThreadLocal&lt;&gt;(); ``` ##### T get() **用途**:返回当前线程所持有的 ThreadLocal 变量的副本。如果这是线程第一次访问,则会创建并初始化该副本。 **示例代码**: ```...

    swift-ThreadlySwift中类型安全的本地线程存储

    例如,可以使用`ThreadLocal&lt;T&gt;`结构体来定义一个线程局部变量,其中`T`是存储值的类型。 4. **线程生命周期管理**:ThreadlySwift会自动管理线程存储的生命周期。当线程结束时,与该线程相关的所有线程局部存储也...

    activiti源码分析

    总结来说,Activiti的工作流源码分析揭示了它在架构设计上的优秀之处,特别是在使用命令模式作为基础开发模型时,对职责分离和解耦所带来的益处。同时,Activiti基于Spring、ibatis等开源中间件的架构选择,为开发...

    SpringBoot整合mybatis-plus实现多数据源的动态切换且支持分页查询.pdf

    public static final ThreadLocal&lt;String&gt; CONTEXT_HOLDER = new ThreadLocal&lt;&gt;(); public static void setDataSource(String dataSource) { CONTEXT_HOLDER.set(dataSource); } public static String get...

    SpringBoot多数据源配置(方式四:根据前端传递的数据库连接参数动态切换数据源).docx

    private static final ThreadLocal&lt;String&gt; contextHolder = new ThreadLocal&lt;&gt;(); public static void setDataSource(String dataSourceName) { contextHolder.set(dataSourceName); } public static ...

    java的ThreadLocal[整理].pdf

    public static ThreadLocal&lt;Integer&gt; thLocal = new ThreadLocal&lt;&gt;(); public static ThreadLocal&lt;String&gt; thLocal2 = new ThreadLocal&lt;&gt;(); public Integer num; public ThreadTest(Integer num) { this....

    JSP通用分页框架

    public static final ThreadLocal&lt;Integer&gt; PAGEINDEX = new ThreadLocal&lt;&gt;(); } ``` 然后,在需要设置或获取这些参数的地方,可以使用`PageParams.PAGESIZE.set()`和`PageParams.PAGEINDEX.set()`来设置值,通过`...

    JDK的ThreadLocal理解(一)使用和测试

    ThreadLocal&lt;String&gt; threadLocal = new ThreadLocal&lt;&gt;(); threadLocal.set("线程A的值"); // 在线程A中,可以获取到设置的值 System.out.println(threadLocal.get()); // 输出 "线程A的值" // 在线程B中,由于没有...

    SpringBoot整合Mybatis连接SQL Server 双数据源配置

    public static final ThreadLocal&lt;String&gt; CONTEXT_HOLDER = new ThreadLocal&lt;&gt;(); public static void setDataSource(String dataSource) { CONTEXT_HOLDER.set(dataSource); } public static String get...

    Springboot实现mybatis多数据源配置

    public static final ThreadLocal&lt;String&gt; THREAD_LOCAL = new ThreadLocal&lt;&gt;(); public static void setDataSource(String dataSource) { THREAD_LOCAL.set(dataSource); } public static String get...

    java8源码-ac_babel:一些后端学习笔记整理

    java8 源码 设计模式 java 并发 public class Foo { // SimpleDateFormat ...ThreadLocal&lt;SimpleDateFormat&gt; ...ThreadLocal&lt;SimpleDateFormat...ThreadLocal&lt;Map&gt;&gt; MAPPING = ThreadLocal.withInitial(HashMap::new); public

    深入理解ThreadLocal工作原理及使用示例

    ThreadLocal&lt;T&gt;简介和使用示例 ThreadLocal只有一个无参的构造方法public ThreadLocal(),它的相关方法包括: * public T get():获取当前线程的变量副本 * public void set(T value):设置当前线程的变量副本 * ...

Global site tag (gtag.js) - Google Analytics