Java 為每個對象關聯一把監視器鎖。synchronized 方法/塊本質是獲取鎖 → 執行臨界區 → 釋放鎖。同一把鎖同一時間只能被一個線程持有。
| 形式 | 鎖對象 | 作用範圍 | 字節碼指令 |
|---|---|---|---|
| 同步實例方法 | this | 整個方法體 | ACC_SYNCHRONIZED 標誌 |
| 同步靜態方法 | Class對象 | 整個方法體 | ACC_SYNCHRONIZED 標誌 |
| 同步代碼塊 | 括號內表達式 | 大括號內代碼 | monitorenter/monitorexit |
public class Test {
public void method1() { synchronized(this) { /* 臨界區 */ } }
public synchronized void method2() { /* 臨界區 */ }
// method1 與 method2 互斥:共用 this 鎖
}
內部類場景:內部類 this 指向內部類實例。若需與外部類同步,用 OuterClass.this:
class Outer {
class Inner {
void method3() { synchronized(Outer.this) { } } // 鎖住外部類實例
}
}
靜態方法無 this,必須用類字面量或 getClass():
public class Test {
public static void method1() { synchronized(Test.class) { } }
public static synchronized void method2() { }
// 兩方法互斥:共用 Test.class 鎖
}
跨類同步:不同類的靜態方法可共享一把 Class 鎖(如 synchronized(SharedClass.class))。
monitorexit 執行。synchronized 涉及用戶態/內核態切換、上下文切換,僅在真正併發寫入共享數據時使用。// ❌ 差:整個方法同步,包含耗時 IO
public synchronized void updateAndLog(Data d) {
compute(d); saveToDB(d); log.info("done");
}
// ✅ 好:只保護共享數據修改
public void updateAndLog(Data d) {
Data copy;
synchronized(this) { copy = compute(d); } // 臨界區極小
saveToDB(copy); log.info("done"); // 耗時操作移出
}
private final Object lock = new Object();(專用鎖,封裝性最好)this / ClassName.class(簡單場景)String、包裝類、常量池對象(可能被無關代碼共享)getClass() 於繼承體系中(子類獲取的是子類 Class,破壞同步語義)掌握 synchronized 的鎖對象語義、靜態/非靜態差異、代碼塊粒度控制,是編寫正確高效併發代碼的基礎。實戰中:優先私有 final 鎖對象、縮小臨界區、避免跨類共享鎖,複雜場景轉用 java.util.concurrent 工具類。