ThreadLocal的作用是为每一个使用该变量的线程提供单独的副本,每个线程可以单独修改属于变量副本而不影响
其他线程的变量副本,这大概也就是ThreadLocal单词中“Local”所要表达的意思,个人理解这个ThreadLocal有点和
volatile相反的意思,好了不多说了,直接上源码吧。。。。。。
先来看set方法
java.lang.ThreadLocal类中
代码段1
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
这一句不用多说,获取当前的运行线程
Thread t = Thread.currentThread();
----------------------------------
下面继续看 getMap(t) 源码
代码段2
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
直接返回当前执行线程对象的 threadLocals 变量,
而这个变量在Thread类中定义为:
代码段3
ThreadLocal.ThreadLocalMap threadLocals = null;
也就是说当前执行线程第一次执行set方法时,threadLocals为null.
在看代码段1,当map为空时,会进入else分支,执行 createMap(t,value)
下面来看此方法的源码
void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }
看到这里,不熟悉的读者可能会有一个疑问, ThreadLocalMap是什么?
ThreadLocalMap 是ThreadLocal的静态内部类,用于保存线程中ThreadLocal的数据结构。ThreadLocal内部就是通过操作ThreadLocalMap从而实现的ThreadLocal的存储。有点类似于HashMap, 对HashMap源码不是很了解的,可能对ThreadLocalMap的源码难以理解. 而ThreadLocalMap又有一个静态内部类Entry,因此,在ThreadLocalMap
中管理的也就是Entry
对象。也就是说,ThreadLocalMap
里面的大部分函数都是针对Entry
的,ThreadLocalMap
里面存储的Entry
对象本质上是一个WeakReference<ThreadLocal>
。也就是说,ThreadLocalMap
里面存储的对象本质是一个对ThreadLocal
对象的弱引用,该ThreadLocal
随时可能会被回收!即导致ThreadLocalMap
里面对应的Value
的Key
是null ,这里为什么使用弱引用不做过多解释。
此段代码以this也即当前ThreadLocal对象作为key, set(T value)方法中的value作为value,创建ThreadLocalMap对象,并赋值给当前执行线程中的threadLocals变量。至此,set(T value)方法执行完毕。
接下来看get方法,其源码为
public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); }
getMap(t) 就是获取当前执行线程所维护的ThreadLocalMap, 如果此map不为空,且存在key为当前ThreadLocal的Entry,则直接返回其值,
如果map为空,则会调用setInitiaValue()方法进行初始化,也即会初始化一个key为当前ThreadLocal,value为null的ThreadLocalMap,并返回null.
remove()方法就不在讲了,如果set get方法都弄清楚了,remove方法不用自己看也就懂了。
至此,ThreadLocal是如何为每一个线程提供独立变量副本的就讲解完毕,不是太难。