ThreadLocal深入浅出
一、分析ThreadLocal源码
ThreadLocal的核心方法一共就几个,get(),set()等等,我们由get()开始,一边分析其源码,一边揭开ThreadLocal的面纱。
先看看JDK7中的get()源码:
public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) return (T)e.value; } return setInitialValue(); }当调用get()方法时,首先会获取当前线程,然后调用getMap方法获取一个ThreadLocalMap对象,我们来看看ThreadLocalMap的源码:
ThreadLocalMap getMap(Thread t) { return t.threadLocals; }很显然,getMap(Thread t)方法用于返回线程的ThreadLocalMap类型成员变量,我们来看看Thread类源码:
ThreadLocal.ThreadLocalMap threadLocals = null;成员变量是一个初始为null的值,ThreadLocalMap是ThreadLocal的一个内部静态类。好了,再回到get()方法,以下代码说明,当ThreadLocalMap对象及其Entry对象皆不为空的时候,返回Entry的value,否则,返回setInitialValue()返回值:
if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) return (T)e.value; } return setInitialValue();
Entry是一个键值对应的关系,维护着ThreadLocal对象和Object对象之间的关系。
setInitialValue()的源码如下:
private T setInitialValue() { T value = initialValue(); Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); return value; }
代码十分简单,新建一个value,当当前线程ThreadLocalMap成员变量为空,则创建map,如果不为空,在map中插入this和value的对应关系,同时返回value。initialValue()是一个protected修饰的方法,用于设置value的默认值,可以重写。
至此就够了,由上文我们可以知道,关键概念是ThreadLocalMap对象,为Thread的成员变量,维护着ThreadLocal对象和Object对象的键值对应关系,可见,一个Thread可以和多个ThreadLocal对象对应,他们之间的关系图如下:
因为,ThreadLocal是弱引用,如果一直没有被引用,势必会被GC回收,此时,Thread中ThreadLocalMap的Entry的key就为空,如果Thread迟迟不结束,value对应的对象就一直不会被释放,造成内存泄露。