ThreadLocal 類提供了線程局部變量,這意味著每個線程都擁有該變量的獨立副本。這是一種避免多線程併發訪問共享變量時發生衝突的有效手段,也可以視為線程同步的另一種實現方式——通過「以空間換時間」的策略,消除同步鎖的開銷。
synchronized 或 ReentrantLock。remove() 避免內存洩漏)。| 方法 | 說明 |
|---|---|
set(T value) | 將當前線程的副本設置為指定值 |
get() | 獲取當前線程的副本值 |
remove() | 移除當前線程的副本,防止內存洩漏 |
initialValue() | 覆寫此方法可提供初始值(延遲初始化) |
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class ThreadLocalDemo {
// 靜態內部類持有 ThreadLocal,確保全局唯一
static class ThreadLocalHolder {
private static final ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>() {
private final Random random = new Random();
@Override
protected Integer initialValue() {
return random.nextInt(10000); // 每個線程首次 get() 時生成專屬隨機數
}
};
static int get() { return threadLocal.get(); }
static void increment() { threadLocal.set(threadLocal.get() + 1); }
}
static class Worker implements Runnable {
private final int id;
Worker(int id) { this.id = id; }
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
ThreadLocalHolder.increment();
System.out.println(this);
Thread.yield();
}
}
@Override
public String toString() {
return "#" + id + ": " + ThreadLocalHolder.get();
}
}
public static void main(String[] args) throws InterruptedException {
ExecutorService executor = Executors.newCachedThreadPool();
for (int i = 0; i < 5; i++) executor.execute(new Worker(i));
TimeUnit.MICROSECONDS.sleep(100); // 讓線程運行一小段時間
executor.shutdownNow();
}
}
輸出示例:
#0: 5255 #1: 9685 #1: 9686 #2: 138 #2: 139 #2: 140 #2: 141 ...
可見每個線程(#0、#1、#2…)擁有獨立的計數器,互不影響。
Android 消息循環機制中,Looper.prepare() 利用 ThreadLocal 為每個線程創建專屬的 Looper 與 MessageQueue:
public final class Looper {
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
// ...
}
這確保了 UI 線程(主線程)與子線程各自擁有獨立的消息隊列,互不阻塞。
static final 修飾:ThreadLocal 實例通常作為類的靜態常量,保證全局唯一。finally 塊中調用 remove(),否則線程復用會導致數據殘留與內存洩漏。ConcurrentHashMap、CopyOnWriteArrayList 等。ThreadLocal 以「線程隔離」換取「無鎖並發」,是高性能併發編程的利器。掌握其原理(ThreadLocalMap 存儲於 Thread 對象中)、生命周期管理與典型應用場景,能幫助你編寫更簡潔、高效的多線程代碼。