ThreadLocal 並非線程的本地實現版本,而是「線程局部變量」。它為每個使用該變量的線程提供獨立的變量副本,各線程可獨立修改自己的副本而不互相干擾。從線程角度看,彷彿每個線程都完全擁有該變量。這在多線程環境下解決線程安全問題極為有效,避免了同步鎖的性能開銷。
Object get():返回當前線程的局部變量副本void set(Object value):設置當前線程的副本值protected Object initialValue():返回初始值,延遲調用,首次 get/set 時執行一次,默認返回 null,通常由子類覆寫ThreadLocal 內部維護一個 Map(實際為 ThreadLocalMap),Key 為當前線程對象,Value 為線程局部變量副本。簡化邏輯如下:
public Object get() {
Thread curThread = Thread.currentThread();
Object o = values.get(curThread);
if (o == null && !values.containsKey(curThread)) {
o = initialValue();
values.put(curThread, o);
}
return o;
}
public void set(Object newValue) {
values.put(Thread.currentThread(), newValue);
}
JDK 實現更為精細,使用 ThreadLocalMap 存儲於 Thread 實例中,Key 為 ThreadLocal 的弱引用,防止內存洩漏。
public class SerialNum {
private static int nextSerialNum = 0;
private static ThreadLocal serialNum = new ThreadLocal() {
@Override
protected synchronized Integer initialValue() {
return nextSerialNum++;
}
};
public static int get() {
return serialNum.get();
}
}
調用 SerialNum.get() 即可獲取當前線程專屬序號。
Web 應用中,每個請求線程持有獨立的數據庫連接或 Hibernate Session,避免多線程共享導致的併發問題。
SimpleDateFormat 非線程安全,使用 ThreadLocal 可為每個線程提供獨立實例:
private static final ThreadLocal dateFormat =
ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
remove() 清理,特別是線程池場景。ThreadLocal 通過「空間換時間」實現線程隔離,是高併發編程利器。理解其 Map 結構、弱引用機制與生命週期管理,能幫助開發者編寫高效、線程安全的代碼。