想像一間只能容納一人的公共廁所。沒有門時,大家衝進去會大亂鬥;裝上門並上鎖,第二人就必須等第一人出來才能進入。這就是互斥存取:共享資源(廁所)同一時間只允許一個執行緒(使用者)進入臨界區(如廁過程)。
在 Java 中,這把「門」就是物件鎖。每個物件天生擁有一把鎖,JVM 透過監視器實現互斥。
synchronized 區塊/方法時,自動嘗試獲取鎖;獲取成功計數器 +1,離開 -1,歸零釋放。static synchronized 鎖住 Xxx.class。public synchronized void doTask() { ... }
鎖住 this。簡單但粒度較粗,整個方法互斥。
public void doTask() {
synchronized(lockObj) { // 指定鎖物件,縮小臨界區
// 核心邏輯
}
}
靈活控制鎖範圍,提升並發度。關鍵:多執行緒必須共用同一個 lockObj 實例。
public static synchronized void staticTask() { ... }
鎖住 CurrentClass.class,所有實例共享這把鎖。
java.util.concurrent.locks.LockLock lock = new ReentrantLock();
lock.lock();
try {
// 臨界區
} finally {
lock.unlock(); // 必須在 finally 釋放
}
優勢:
lockInterruptibly())。tryLock(timeout))。Condition 實現精細等待/通知。ThreadLocal ── 空間換時間,無鎖並發不共享、就不需同步。ThreadLocal 為每個執行緒提供獨立副本:
ThreadLocal threadLocal = new ThreadLocal<>();
threadLocal.set(1); // 當前執行緒專屬
Integer val = threadLocal.get();
remove() 防止記憶體洩漏。| 場景 | 推薦方案 |
|---|---|
| 簡單共享變數、低競爭 | synchronized 方法/區塊 |
| 需可中斷、逾時、公平鎖、多條件變數 | ReentrantLock |
| 執行緒獨享資料、高並發無狀態 | ThreadLocal |
| 計數器、累加器等原子操作 | AtomicLong 等原子類別 |
同步本質是協調共享資源存取順序。理解 JVM 物件鎖、監視器、可重入機制,才能正確選擇 synchronized、Lock 或 ThreadLocal。現代開發優先考慮無鎖設計(ThreadLocal、原子類別、不可變物件),必要時再用精細鎖控制,避免過度同步導致效能瓶頸與死鎖風險。