單執行緒無安全問題。多執行緒同時存取共享資源(變數、物件、檔案、資料庫)且執行順序不可控時,可能導致結果與預期不符或程式崩潰。
兩執行緒同時讀取資料 X → 同時檢查資料庫無 X → 同時插入 X → 產生重複資料。此時資料庫表為臨界資源。
採用同步互斥:同一時間僅允許一執行緒存取臨界資源。Java 提供兩種機制:synchronized 與 Lock。
public synchronized void insert(Thread t) {
for (int i=0; i<5; i++) {
System.out.println(t.getName() + " 插入 " + i);
list.add(i);
}
}
效果:執行緒順序執行,Thread-0 完成後 Thread-1 才開始。
public void insert(Thread t) {
synchronized (this) { // 或 synchronized (lockObject)
// 僅此處同步,粒度更細
}
}
優勢:僅同步必要區段,提升並發效能。
| 規則 | 說明 |
|---|---|
| 一個物件一把鎖 | 執行緒進入同步方法/塊需獲得物件鎖 |
| 同步方法互斥 | 執行緒 A 在同步方法中,執行緒 B 無法進入同一物件的其他同步方法 |
| 非同步方法不受影響 | 執行緒 B 仍可呼叫非同步方法 |
| 不同物件互不干擾 | 物件 A 的同步方法不阻擋物件 B 的同步方法 |
| 異常自動釋放鎖 | JVM 保證異常時釋放鎖,不會死鎖 |
public synchronized void instanceMethod() { ... } // 鎖:this (實例)
public static synchronized void staticMethod() { ... } // 鎖:Class 物件
ACC_SYNCHRONIZED,JVM 自動進入/退出時獲取/釋放鎖monitorenter / monitorexit 指令對,對應鎖計數器 +1/-1synchronizedString、Integer 等常量池物件可能導致非預期共享鎖tryLock(timeout)(需 Lock 介面)synchronized 效能已大幅提升ReentrantLock(公平鎖、可中斷、條件變數)ReentrantReadWriteLock 或 StampedLock