synchronize 一詞源自「使同時發生」,但 Java 線程同步的真實含義恰恰相反——強制線程排隊,逐個訪問共享資源。理解這一點,是掌握併發安全的鑰匙。本文從四大核心原則、生活類比、代碼實戰三個維度,徹底講透 Java 線程同步鎖。
兩名採購員各自買樣品、寫報告,互不干擾 —— 兩線程操作各自私有數據,無共享,無同步。
採購員同時看「布告欄」(只讀資源),互不影響 —— 多線程並發讀取不可變數據,安全。
行政人員修改布告欄時,採購員必須等待;採購員閱讀時,行政人員必須等待。一寫多讀、寫寫互斥,這就是同步的核心場景。注意:行政與採購員代碼邏輯完全不同,但因訪問同一可變資源(布告欄),依然需要同步 —— 驗證原則四。
Java 提供兩種內置鎖機制:
// 1. 同步代碼塊:鎖對象任意,推薦用共享資源實例或專用鎖對象
synchronized (lockObject) {
// 临界區:訪問共享資源
}
// 2. 同步方法:鎖隱式為 this (實例方法) 或 Class 對象 (靜態方法)
public synchronized void modifyShared() { ... }
鎖的語義:獲得鎖的線程進入臨界區,其他線程阻塞等待,釋放鎖喚醒等待者。這與超市儲物箱「一把鎖一把鑰匙」完全同構。
new Object()、字符串常量、基本類型包裝對象作為鎖,導致實際未共享同一把鎖;tryLock 超時機制;public class SafeCounter {
private int count = 0;
private final Object lock = new Object(); // 專用鎖對象
public void increment() {
synchronized (lock) { // 僅保護核心寫操作
count++;
}
}
public int getCount() {
synchronized (lock) { // 讀也要同步,保證可見性
return count;
}
}
}
對比 AtomicInteger:CAS 無鎖方案在低競爭下性能更優,高競爭下鎖可能更穩定,按場景選型。
Java 線程同步的本質是互斥訪問可變共享狀態。牢記「共享、可變、訪問」三要素,選對鎖對象、縮小臨界區、防死鎖,即可構建健壯併發程序。下一步可深入學習 ReentrantLock、ReadWriteLock、StampedLock 等顯式鎖,以及 java.util.concurrent 並發包的高級組件。