疯狂餐厅
86.88M · 2026-03-21
private final int threadLocalHashCode = nextHashCode();
private static AtomicInteger nextHashCode = new AtomicInteger();
private static final int HASH_INCREMENT = 0x61c88647;
private static int nextHashCode() {
return nextHashCode.getAndAdd(HASH_INCREMENT);
}
ThreadLocalMapThreadLocalMap 是 ThreadLocal 的静态内部类,它是真正存储线程局部变量的地方。每个线程(Thread 对象)都持有一个 ThreadLocalMap 类型的引用(threadLocals)。
static class Entry extends WeakReference<ThreadLocal<?>> {
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
private Entry[] table; // 哈希表,长度必须是 2 的幂
private int size; // 实际存储的 Entry 数量
private int threshold; // 扩容阈值,默认是 table 长度的 2/3
ThreadLocalMap 采用开放地址法(线性探测)解决哈希冲突,而不是 HashMap 的链地址法。这是因为 Entry 数量通常较小,线性探测在缓存局部性上更有优势。
set(T value):设置当前线程的局部变量public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
ThreadLocalMap.set() 的核心逻辑
private void set(ThreadLocal<?> key, Object value) {
Entry[] tab = table;
int len = tab.length;
int i = key.threadLocalHashCode & (len-1); // 计算桶索引
for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) {
ThreadLocal<?> k = e.get();
if (k == key) { // 找到相同 key,直接替换 value
e.value = value;
return;
}
if (k == null) { // 遇到过期 Entry(key 已被 GC),执行替换
replaceStaleEntry(key, value, i);
return;
}
}
// 找到空槽,创建新 Entry
tab[i] = new Entry(key, value);
int sz = ++size;
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash(); // 扩容或重新散列
}
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();
}
ThreadLocalMap.getEntry() 的核心逻辑
private Entry getEntry(ThreadLocal<?> key) {
int i = key.threadLocalHashCode & (table.length - 1);
Entry e = table[i];
if (e != null && e.get() == key)
return e;
else
return getEntryAfterMiss(key, i, e);
}
remove():移除当前线程的局部变量public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}
每个 Thread 对象内部持有两个 ThreadLocalMap 类型的字段:
ThreadLocal.ThreadLocalMap threadLocals = null; // 普通 ThreadLocal
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null; // 可继承的 ThreadLocal
这两个字段通过 ThreadLocal 的 getMap(Thread t) 和 createMap(Thread t, T firstValue) 方法进行访问和初始化。
Entry 使用 WeakReference<ThreadLocal<?>> 作为键,意味着如果外部不再持有 ThreadLocal 对象的强引用,GC 回收 ThreadLocal 后,Entry 的键会变为 null。但 Entry.value 仍然是强引用,如果线程持续存活(如线程池中的线程),这些 value 就可能无法被回收,造成内存泄漏。