注意ThreadLocalMap是使用弱引用来保存ThreadLocal对象
1)ThreadLocal的介绍
ThreadLocal是一个线程的内部存储类,可以在每个线程的内部存储数据,当某个数据的作用域应该对应线程的时候就应该使用它;
而是当某个很复杂的逻辑下的对象传递,需要在线程这个作用域内贯穿其中,用ThreadLocal可以避免这个创建多个静态类。
当你创建一个ThreadLocal对象后,注意,是一个对象,你在不同线程中去访问它的值是可以不一样的,并且是和线程相关联的。
它的实现原理其实比较简单,每个线程中都会维护一个ThreadLocalMap,当在某个线程中访问时,会取出这个线程自己的Map并且用当前ThreadLocal对象做索引来取出相对应的Value值,从而达到不同线程不同值的效果。
(2)实现原理
1、每个Thread对象内部都维护了一个ThreadLocalMap这样一个ThreadLocal的Map,可以存放若干个ThreadLocal。
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
2、当我们在调用get()方法的时候,先获取当前线程,然后获取到当前线程的ThreadLocalMap对象,如果非空,那么取出ThreadLocal的value,否则进行初始化,初始化就是将initialValue的值set到ThreadLocal中。
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();
}
3、当我们调用set()方法的时候,很常规,就是将值设置进ThreadLocal中。
4、ThreadLocalMap里面存储的Entry对象本质上是一个WeakReference<ThreadLocal>。
static class ThreadLocalMap {
/**
* The entries in this hash map extend WeakReference, using
* its main ref field as the key (which is always a
* ThreadLocal object). Note that null keys (i.e. entry.get()
* == null) mean that the key is no longer referenced, so the
* entry can be expunged from table. Such entries are referred to
* as "stale entries" in the code that follows.
*/
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
也就是说,ThreadLocalMap里面存储的对象本质是一个对ThreadLocal对象的弱引用,该ThreadLocal随时可能会被回收!
即导致ThreadLocalMap里面对应的Value的Key是null。我们需要把这样的Entry给清除掉,不要让它们占坑,避免内存泄漏。
那为什么需要弱引用呢?
因为线程的生命周期是长于ThreadLocal对象的生命周期,当此对象不再需要的时候如果线程中还持有它的引用势必也会产生内存泄漏的问题,所以自然应该是用弱引用来进行key的保存。