多線程並發訪問共享可變數據時,會出現原子性違反(如 i++ 非原子)、可見性問題(缓存未刷新)、有序性問題(指令重排)。同步機制保證臨界區同一時刻僅一線程執行。
public synchronized void deposit(int amount) {
balance += amount; // 隱式鎖:this
}
public static synchronized void staticMethod() {
// 隱式鎖:ClassName.class
}
public void withdraw(int amount) {
synchronized (this) { // 或私有鎖對象
if (balance >= amount) balance -= amount;
}
}
// 私有鎖對象模式(封裝性更好)
private final Object lock = new Object();
public void transfer(Account target, int amt) {
synchronized (lock) {
synchronized (target.lock) { // 注意:固定獲取順序防死鎖
this.withdraw(amt);
target.deposit(amt);
}
}
}
| 場景 | 鎖行為 |
|---|---|
| 進入 synchronized 區塊 | 嘗試獲取鎖,失敗則進入阻塞隊列 |
| 正常退出區塊 | 釋放鎖,喚醒阻塞隊列一線程 |
| 拋出異常退出 | 自動釋放鎖 |
調用 wait() | 釋放鎖,進入等待集 |
調用 sleep()/yield() | 不釋放鎖 |
Object Header (64-bit):
| Mark Word (64 bits) | Klass Pointer |
| hash(25) | age(4) | bias(1) | lock(2) | epoch(32) | ... |
鎖狀態流向:
無鎖 → 偏向鎖 → 輕量級鎖 → 重量級鎖
(CAS) (CAS自旋) (OS互斥量)
| 錯誤代碼 | 問題 | 修正 |
|---|---|---|
synchronized(new Object()) | 每次新對象,無同步效果 | 用共享 final 鎖對象 |
synchronized(String.class) 配合 synchronized(this) | 鎖對象不同,互不阻塞 | 統一鎖對象 |
| 鎖住長耗時操作 (IO、sleep) | 吞吐率極低 | 縮小臨界區,異步化 |
| 雙重檢查鎖單例 (無 volatile) | 指令重排導致半初始化對象 | 加 volatile 或用內部類 |
ReentrantLock:可中斷、可超時、公平鎖、多條件 ConditionReadWriteLock:讀讀並行、讀寫互斥StampedLock:樂觀讀、更高並發AtomicLong/LongAdder:無鎖計數器ConcurrentHashMap:分段鎖/CAS 無鎖 Mapjava.util.concurrent 高級組件,減少手寫 synchronizedprivate final Object lock = new Object() 封裝鎖ReadWriteLock 或 StampedLock理解 synchronized 底層機制,是排查死鎖、活鎖、性能抖動的基礎。