並發編程核心矛盾:效率與一致性的博弈。共享可變狀態是線程安全問題根源,synchronized 提供互斥訪問保證。
非原子操作 m++ 拆解為:讀取 → 修改 → 寫入。多線程交替執行導致更新丟失:
private static volatile int m = 0; // 兩線程各執行 10000 次 m++,預期 20000,實際 < 20000
// 鎖對象實例
synchronized (this) { m++; }
// 鎖自定義對象(推薦:封裝性更好)
private final Object lock = new Object();
synchronized (lock) { m++; }
// 實例方法:鎖 this
public synchronized void run() { m++; }
// 靜態方法:鎖 Class 對象
public static synchronized void count() { m++; }
錯誤示例:每次 new Runnable 創建線程,導致同步方法鎖住不同實例:
// 錯誤:兩個線程持有不同鎖 new Thread(new SynchronizedTest()).start(); new Thread(new SynchronizedTest()).start(); // 正確:共享同一 Runnable 實例 Runnable task = new SynchronizedTest(); new Thread(task).start(); new Thread(task).start();
將核心邏輯提取為 static synchronized 方法,鎖住 SynchronizedTest.class,JVM 僅加載一次 Class 對象,天然全局唯一:
public void run() { for(...) count(); }
public static synchronized void count() { m++; }
monitorenter/monitorexit 字節碼指令實現final Object lock = new Object(),避免鎖對象被替換synchronized 是 JVM 內建的重量級鎖(JDK 1.6+ 引入偏向鎖、輕量級鎖優化),理解其語義與陷阱,是寫正確並發代碼的基石。