ThreadLocal 不是儲存值的地方,它只是一個「鑰匙」。真正的倉庫是 Thread 內部的 ThreadLocalMap,Key 就是 ThreadLocal 實例本身。
// ThreadLocal.get()
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t); // 取當前線程的 map
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this); // this 即 ThreadLocal 實例作為 Key
if (e != null) return (T)e.value;
}
return setInitialValue(); // 首次調用初始化
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals; // Thread 類的私有字段
}

假設當前線程 Thread@1 有 threadLocals = ThreadLocalMap@432:
firstNum.set(100) → Map 中 Key=ThreadLocal@428, Value=100secondNum.set(200) → Map 中 Key=ThreadLocal@430, Value=200thirdNum.set(300) → Map 中 Key=ThreadLocal@429, Value=300

Thread.threadLocals:ThreadLocalMap,線程私有。ThreadLocalMap.Entry:繼承 WeakReference<ThreadLocal>,**Key 是弱引用**!| 方法 | 作用 |
|---|---|
initialValue() | 延遲初始化,首次 get() 觸發,默認返回 null,可覆寫。 |
get() | 從當前線程 Map 取值,無則初始化。 |
set(T value) | 向當前線程 Map 放值。 |
remove() | 從當前線程 Map 刪除條目,**防內存洩漏必調用**。 |
若 ThreadLocal 實例不再被外部引用,GC 可回收 Key,Map 中的 Entry 變為 key=null,下次 get/set/remove 會清理這些「陰影條目」,避免 Value 永遠無法釋放(內存洩漏)。但 Value 本身是強引用,若線程長期存活(如線程池),必須手動 remove()。
private static final ThreadLocal<UserContext> CTX = new ThreadLocal<>();
public void doSomething() {
CTX.set(buildContext());
try { businessLogic(); }
finally { CTX.remove(); } // 釋放 Value,斷開引用鏈
}
TransmittableThreadLocal (阿里開源) 使用。ThreadLocal = Key,Thread.threadLocals = Map,Entry.key = WeakReference(ThreadLocal)。理解這張圖,ThreadLocal 的所有行為(隔離、洩漏、繼承、清理)就都通透了。