ThreadLocal 源码:线程本地副本原理¶
一、是什么¶
每个线程有自己的变量副本,多线程间互不影响。
二、结构¶
每个 Thread 对象内部有一个 ThreadLocalMap:
ThreadLocalMap 是个自定义哈希表:
ThreadLocalMap
└── Entry[] table
└── Entry extends WeakReference<ThreadLocal>
├── key: ThreadLocal(弱引用)
└── value: 实际值
为什么 key 是弱引用¶
如果 key 是强引用,ThreadLocal 对象被回收后,Entry 还在,value 也在,造成内存泄漏。
弱引用:ThreadLocal 没别的引用时,GC 会回收 key,Entry 变 null。
三、set 流程¶
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
- 拿当前线程。
- 拿线程的 threadLocals。
- 以 ThreadLocal 对象为 key,存 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) return (T)e.value;
}
return setInitialValue();
}
五、内存泄漏¶
即使 key 是弱引用,value 是强引用。如果线程长期存在(线程池),Entry 的 key 被回收成 null,但 value 还在,没人访问,泄漏。
解决¶
用完手动 remove():
六、ThreadLocalMap 的 hash¶
用 threadLocalHashCode 递增,避免哈希冲突。不是常见的乘除法 hash。
高频考点
- ThreadLocal 不是"线程隔离",是"每个线程一个 Map"。
- 父子线程传值用 InheritableThreadLocal。
- 线程池一定要 remove!