ThreadLocal是线程私有的,各个线程之间是隔离的。可以想象一下每次线程创建的时候在堆上预先分配一个内存空间用于存储ThreadLocal的数据。
(1)当线程被创建时,线程都会有一个成员变量ThreadLocalMap。
//每个线程定义一个成员变量 ThreadLocalMap。
public class Thread implements Runnable {/* ThreadLocal values pertaining to this thread. This map is maintained* by the ThreadLocal class. */ThreadLocal.ThreadLocalMap threadLocals = null;}
(2)当ThreadLocal第一次调用Set(Value)存储的时候。ThreadlocalMap被实例化。
public class ThreadLocal<T> {/*** Sets the current thread's copy of this thread-local variable* to the specified value. Most subclasses will have no need to* override this method, relying solely on the {@link #initialValue}* method to set the values of thread-locals.** @param value the value to be stored in the current thread's copy of* this thread-local.*/public void set(T value) {Thread t = Thread.currentThread();ThreadLocalMap map = getMap(t);if (map != null) {map.set(this, value);} else {// 第一次创建ThreadLocalMap对象。createMap(t, value);}}/*** Create the map associated with a ThreadLocal. Overridden in* InheritableThreadLocal.** @param t the current thread* @param firstValue value for the initial entry of the map*/void createMap(Thread t, T firstValue) {// 创建ThreadLocalMap对象,并且赋值给当前线程的成员变量。t.threadLocals = new ThreadLocalMap(this, firstValue);}
}
(3)创建Entry[16]数组,封装Entry对象ThreadLocal作为key一一对应。
public class ThreadLocal<T> { static class ThreadLocalMap {/*** The initial capacity -- MUST be a power of two.*/private static final int INITIAL_CAPACITY = 16;/*** The table, resized as necessary.* table.length MUST always be a power of two.*/private Entry[] table;/*** Construct a new map initially containing (firstKey, firstValue).* ThreadLocalMaps are constructed lazily, so we only create* one when we have at least one entry to put in it.*/ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {//创建16位Entry数组,并且初始化Entry[]的成员变量。table = new Entry[INITIAL_CAPACITY];int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);//把ThreadLoacl对象最为key,封装到entry对象数组里面。table[i] = new Entry(firstKey, firstValue);size = 1;setThreshold(INITIAL_CAPACITY);}/*** 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的对象。Entry(ThreadLocal<?> k, Object v) {super(k);value = v;}}}
}
(4)ThreadLocal<?>对象被弱引用对象WeakReference封装,随时可能会被GC回收。不管内存是否充足。
思考一个问题?如果ThreadLocal对象被回收了,那么ThreadLocalMap里面的Enrty<K,V>数组元素Entry没有Key怎么办?Value值怎么获取?Entry<null,V> 越来越多是否会出现内存泄漏?
【Java并发编程】ThreadLocal(三):内存泄漏问题分析_threadlocalref-CSDN博客