在 synchronized 中使用 Boolean、Integer、String 等不可變包裝類/常量作為鎖,極易引發兩類隱蔽 Bug:
private volatile Boolean running = false;
public void toggle() {
synchronized (running) {
running = !running; // 裝箱後 running 指向 Boolean.TRUE/FALSE
// 其他線程可能持有舊 Boolean 對象的鎖,並發執行臨界區
}
}
多線程並發測試會觀察到臨界區被同時進入,輸出「同步失效」。
private Boolean lockA = Boolean.FALSE;
private Boolean lockB = false; // 同一常量對象
public void taskA() { synchronized(lockA) { /* 耗時操作 */ } }
public void taskB() { synchronized(lockB) { /* 耗時操作 */ } }
本應並行的 taskA 和 taskB 因共享 Boolean.FALSE 而串行執行,性能大幅下降。
// 方案一:Object 鎖(推薦) private final Object lock = new Object(); // 方案二:new 包裝類(每次 new 創建新對象) private final Boolean lock = new Boolean(false); // 方案三:ReentrantLock 顯式鎖 private final Lock lock = new ReentrantLock();
synchronized(包裝類變量)?synchronized(字符串字面量)?synchronized(基本類型包裝類字段)?private final Object 專用鎖?| 類型 | 風險 | 示例 |
|---|---|---|
| Integer | -128~127 常量池共享 | synchronized(count) count 為 Integer |
| String | 字面量/ intern() 共享 | synchronized("LOCK") |
| Long | -128~127 常量池 | 同 Integer |