本文基於 Java Language Specification (JLS) 與 Java Virtual Machine Specification (JVMS),從 JVM 角度剖析 Java 線程的語法語義、synchronized 編譯產物、監視器指令、線程與鎖的內存模型語義,幫助開發者透過現象看本質,理解併發底層機制。
JLS §8.4.3.6 規定:
this(當前對象實例)。Class 對象。等價轉換示例:
// 代碼 1:同步方法
class Test {
synchronized void bump() { count++; }
static synchronized void classBump() { classCount++; }
}
// 代碼 2:等價同步塊
class Test {
void bump() { synchronized(this) { count++; } }
static void classBump() {
synchronized(Test.class) { classCount++; } // Class.forName("Test") 同理
}
}
兩者語義完全一致,編譯器將同步方法標記為 ACC_SYNCHRONIZED 訪問標誌,而非生成 monitorenter/monitorexit 指令。
JVMS §7.11 規定:
方法訪問標誌設置 ACC_SYNCHRONIZED(0x0020)。JVM 調用方法時檢查此標誌,自動執行鎖獲取/釋放邏輯(隱式 monitorenter/monitorexit)。無額外字節碼指令。
編譯為顯式 monitorenter / monitorexit 指令對。示例:
void onlyMe(Foo f) {
synchronized(f) { doSomething(); }
}
編譯為(簡化):
Method void onlyMe(Foo)
0 aload_1 // 載入 f
1 astore_2 // 存入局部變量 2 (隱式鎖變量)
2 aload_2 // 載入鎖對象
3 monitorenter // 獲取鎖
4 aload_0 // this
5 invokevirtual #5 // 調用 doSomething()
8 aload_2 // 載入鎖對象
9 monitorexit // 釋放鎖 (正常退出)
10 return
11 aload_2 // 異常路徑入口
12 monitorexit // 釋放鎖 (異常退出)
13 athrow // 重拋異常
關鍵點:編譯器在正常退出與異常退出路徑各插入一條 monitorexit,確保鎖必釋放(類似 finally 語義)。
reference 類型(對象引用,即堆地址)。注意:monitor 是 JVM 規範內部概念,Java 語言/API 文檔中不直接暴露,它是 synchronized、Object.wait/notify、java.util.concurrent.locks 的統一底層抽象。
JVMS §8 定義了線程交互的核心規則,重點章節:
這些規範是 java.util.concurrent、JMM(Java Memory Model)、JIT 優化合法性的基石。
Java、C# 等生成中間代碼的語言,其運行行為由虛擬機規範嚴格定義。規範是:
直接閱讀 JLS/JVMS 一手資料,能避免二手資料的信息失真,構建精確的心智模型。
CLI ECMA-335 定義了類似但不同的線程與同步模型(如 monitor.enter/exit、volatile. 前綴指令、MethodImplOptions.Synchronized)。對比研究有助於理解托管運行時併發設計的共性與差異。
掌握 JVM 層面的線程語義,是進階為併發專家、排查疑難併發 Bug、設計高性能同步組件的必經之路。