ThreadLocal<T>类在Spring,Hibernate等框架中起到了很大的作用,对于其工作原理,很多网上的文章分析的不够彻底,甚至有些误解。
首先,为了解释ThreadLocal类的工作原理,必须同时介绍与其工作甚密的其他几个类(内部类)
1.ThreadLocalMap
2.Thread
可能有人会觉得Thread与ThreadLocal有什么关系,其实真正的奥秘就在Thread类中的一行:
ThreadLocal.ThreadLocalMap threadLocals = null;
其中ThreadLocalMap的定义是在ThreadLocal类中,真正的引用却是在Thread类中。
那么ThreadLocalMap究竟是什么呢?
可以看到这个类应该是一个Map,JDK的解释是:
接下来的重点是ThreadLocalMap中用于存储数据的entry:
static class Entry extends WeakReference<ThreadLocal> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal k, Object v) { super(k); value = v; } }
从中我们可以发现这个Map的key是ThreadLocal变量,value为用户的值,并不是网上大多数的列子key是线程的名字或者标识
到这里,我们就可以理解ThreadLocal究竟是如何工作的了。
1.Thread类中有一个成员变量叫做ThreadLocalMap,它是一个Map,他的Key是ThreadLocal类
2.每个线程拥有自己的申明为ThreadLocal类型的变量,所以这个类的名字叫'ThreadLocal':线程自己的(变量)
3.此变量生命周期是由该线程决定的,开始于第一次初始(get或者set方法)
4.由ThreadLocal的工作原理决定了:每个线程独自拥有一个变量,并非共享或者拷贝。
/** * @author mxdba * */ public class ThreadLocalSample { public static void main(String[] args) { ThreadTest test1 = new ThreadTest(10); ThreadTest test2 = new ThreadTest(20); test1.start(); test2.start(); } } /** * 此线程有两个ThreadLocal变量,但是由于ThreadLocal是延迟初始的, * 所以在debug时可以看到线程名为“线程20”的线程的ThreadLocalMap中没有thLcal2这个entry * @author mxdba * */ class ThreadTest extends Thread { public static ThreadLocal<Integer> thLocal = new ThreadLocal<Integer>(); public static ThreadLocal<String> thLocal2 = new ThreadLocal<String>(); public Integer num; public ThreadTest(Integer num) { super("线程" + num); this.num = num; } @Override public void run() { Integer n = thLocal.get(); if(num != 20) { String s = thLocal2.get(); } if(n == null) { thLocal.set(num); } System.out.println(thLocal.get()); } }
接下来分析一下源码,就更加清楚了。