synchronized 是 Java 並發編程的基石關鍵字,基於對象監視器實現互斥同步。本文通過銀行賬戶轉賬模擬,演示同步方法、靜態同步與非靜態同步的鎖對象差異,並總結 synchronized 與 Lock 的選型建議。
this、靜態方法鎖 Class 對象、同步塊鎖指定對象。Account:余額 balance,synchronized addAmount/subtractAmount。Company/Bank 實現 Runnable,分別並發 100 次存/取 1000。join() 等待完成,驗證最終餘額等於初始值。class Account {
private double balance;
public synchronized void addAmount(double amount) {
double tmp = balance;
Thread.sleep(10); // 放大並發窗口
tmp += amount;
balance = tmp;
}
public synchronized void subtractAmount(double amount) { ... }
}
Account : Initial Balance: 1000.000000
Account : Final Balance: 1000.000000 // 始終一致
去掉 synchronized:最終餘額隨機偏離 1000,多次運行結果不一,證明數據競態。
Account 實例的兩個同步方法互斥:線程 A 執行 addAmount 時,線程 B 嘗試 subtractAmount 會阻塞。Account 實例互不干擾:各自鎖各自的 this。class Account {
private static double balance = 0; // 靜態共享
public static synchronized void addAmount(double amount) { ... } // 鎖 Account.class
public synchronized void subtractAmount(double amount) { ... } // 鎖 this
}
最終餘額不再固定,每次運行結果不同。
原因:addAmount 鎖 Account.class,subtractAmount 鎖具體實例 this,兩把鎖互不相干,線程可同時進入,發生競態。
synchronized(Account.class) { ... }。| 特性 | 說明 | 對比 Lock |
|---|---|---|
| 實現層級 | JVM 內部(監視器進入/退出字節碼) | JDK API (AQS) |
| 公平性 | 非公平,新線程可搶佔,防饑餓 | 可選公平/非公平 |
| 條件等待 | 單一 wait/notify,不靈活 | Condition 支持多條件隊列 |
| 中斷響應 | 不可中斷,只能等待獲取鎖 | lockInterruptibly() 可響應中斷 |
| 性能 | JDK 6+ 鎖優化後極具競爭力 | 高並發下可優於未優化 synchronized |
Condition/中斷/公平鎖。String/包裝類/集合等可能被複用的對象,專用 private final Object lock = new Object();。tryLock 超時、避免持有鎖調用外部方法。掌握 synchronized 的鎖對象語義與 JVM 優化機制,是寫出高性能線程安全代碼的前提。