ThreadLocal(線程局部變量)為每個線程提供獨立的變量副本,解決多線程環境下共享變量的並發衝突。JDK 1.2 引入,JDK 5.0 支持泛型 ThreadLocal<T>。
void set(T value):設置當前線程副本值。T get():獲取當前線程副本值。void remove():刪除當前線程副本(加速 GC)。protected T initialValue():子類覆蓋提供初始值,首次 get/set 時調用一次。public class TestNum {
private static ThreadLocal<Integer> seqNum = new ThreadLocal<Integer>() {
@Override protected Integer initialValue() { return 0; }
};
public int getNextNum() {
seqNum.set(seqNum.get() + 1);
return seqNum.get();
}
public static void main(String[] args) {
TestNum sn = new TestNum();
new Thread(() -> { for (int i=0;i<3;i++) System.out.println(Thread.currentThread().getName()+" -> "+sn.getNextNum()); }).start();
new Thread(() -> { for (int i=0;i<3;i++) System.out.println(Thread.currentThread().getName()+" -> "+sn.getNextNum()); }).start();
new Thread(() -> { for (int i=0;i<3;i++) System.out.println(Thread.currentThread().getName()+" -> "+sn.getNextNum()); }).start();
}
}
// 輸出:每個線程獨立從 1 開始遞增,互不干擾
| 維度 | synchronized (鎖) | ThreadLocal (副本) |
|---|---|---|
| 思路 | 以時間換空間:單份變量,線程排隊訪問 | 以空間換時間:每線程一份,並行無衝突 |
| 適用場景 | 臨界區邏輯複雜、操作非線程安全對象 | 變量本身可獨立、業務邏輯無共享狀態 |
| 性能 | 上下文切換開銷大,高併發下吞吐率低 | 無鎖,極高併發性能 |
| 內存 | 低 | 高(隨線程數線性增長) |
每個 Thread 實例內部持有 ThreadLocal.ThreadLocalMap threadLocals,Map 的 Key 是 ThreadLocal 對象本身,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 getMap(Thread t) { return t.threadLocals; }
void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }
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(); // 首次調用,執行 initialValue()
}
WeakReference<ThreadLocal>,Key 為弱引用。remove() 或線程結束釋放。Spring 將有狀態但需線程隔離的組件(RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder)封裝在 ThreadLocal 中,使其成為線程安全的單例 Bean,可安全注入多線程環境。
public class ConnectionManager {
private static ThreadLocal<Connection> holder = new ThreadLocal<Connection>() {
@Override protected Connection initialValue() {
return DriverManager.getConnection(url, user, pass);
}
};
public static Connection getConnection() { return holder.get(); }
public static void setConnection(Connection conn) { holder.set(conn); }
}
// 事務管理器開啟事務時:ConnectionManager.setConnection(con);
// 多個 DAO 調用 ConnectionManager.getConnection() 獲取同一連接
// 事務結束:holder.remove();
remove(),防止內存洩漏與數據串聯。ThreadLocal 以「空間換時間」實現無鎖線程隔離,是高併發系統中的利器。理解其 Thread → ThreadLocalMap → Entry(ThreadLocal, Value) 三層結構,掌握 set/get/remove 生命周期,結合 Spring 事務管理等實戰場景,即可靈活駕馭多線程狀態管理。