首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

JVM 並發編程:Java 內存模型 (JMM) 核心規範與 Happens-Before 原則深度解析

     編輯:Java 綜合教學

前言

Java 內存模型 (JMM) 是並發編程的基石,定義了線程與主內存交互的語義規範。本文系統梳理 JMM 核心概念(主內存/工作內存、八大操作、volatile/long/double 特殊規則)、三大特性(原子性/可見性/有序性)、以及 Happens-Before 八大法則,構建並發正確性推理的理論基石。

一、主內存與工作內存

  • 主內存:共享內存區域,存儲所有實例對象、靜態字段、數組元素等共享變量
  • 工作內存:線程私有,存儲共享變量的副本 (緩存行、寄存器、編譯器優化後的值)
  • 交互規則:線程只能操作工作內存,讀寫主內存需通過八大原子操作;線程間通信必須經主內存中轉

二、內存交互八大原子操作

操作作用對象語義配對關係
lock (鎖定)主內存變量標識變量為線程獨佔lock/unlock 配對
unlock (解鎖)主內存變量釋放獨佔狀態,允許其他線程鎖定
read (讀取)主內存變量從主內存傳輸值到線程緩存read/load 配對
load (載入)工作內存變量將 read 獲取的值放入工作內存副本
use (使用)工作內存變量將工作內存值傳遞給執行引擎use/assign 配對
assign (賦值)工作內存變量將執行引擎接收的值賦給工作內存副本
store (存儲)工作內存變量將工作內存值傳輸到主內存緩存store/write 配對
write (寫入)主內存變量將 store 獲取的值寫入主內存變量

三、操作約束規則 (JMM 強制要求)

  1. 配對完整性:不允許 read/load、store/write 單獨出現 (即不允許只讀不載入、只存不寫入)
  2. 不丟棄賦值:線程對工作內存的 assign 操作結果,必須最終同步回主內存 (store/write)
  3. 無因同步禁止:未發生 assign 操作,不允許將工作內存數據同步回主內存
  4. 變量誕生規則:新變量只能在主內存「誕生」;工作內存不可直接使用未初始化變量 (use/store 前必須經 assign/load)
  5. 鎖唯一性:同一時刻僅允許一線程 lock 同一變量;可重入 (同一線程多次 lock);需同次數 unlock 才釋放
  6. 鎖清空副本:lock 操作清空工作內存該變量副本;使用前需重新 load/assign 初始化
  7. 非法解鎖禁止:未 lock 的變量不可 unlock;不可 unlock 其他線程鎖定的變量
  8. 解鎖前同步:unlock 前必須先 store/write 將變量同步回主內存

四、特殊類型變量規則

1. volatile 變量特殊語義

  • 可見性保證:對 volatile 寫入對所有線程立即可見 (實際上:寫入前插入 StoreLoad 屏障,讀取後插入 LoadLoad+LoadStore 屏障)
  • 禁止指令重排序:編譯器/處理器不會將 volatile 讀寫與相鄰內存操作重排序
  • 非原子性:volatile 僅保證單次讀/寫原子,複合操作 (如 volatile int i; i++) 仍非原子,需配合 AtomicInteger 或 synchronized

2. long/double 非原子性協定

  • JMM 允許將未被 volatile 修飾的 64 位讀寫拆分為兩次 32 位操作
  • 即:load/store/read/write 四操作可不保證 64 位原子性
  • 實踐建議:多線程環境下 64 位數據 (long/double) 必須聲明 volatile 或使用 AtomicLong/AtomicDouble/LongAdder/DoubleAdder

五、並發三大特性

特性定義JMM 保障機制典型手段
原子性操作不可分割,要么全做要么全不做八大操作本身原子;synchronized/Lock 保證代碼塊原子synchronized、Lock、Atomic*、CAS
可見性線程修改共享變量,其他線程立即可見volatile 強制刷新/失效緩存;synchronized/unlock 同步回主內存volatile、synchronized、final、Lock
有序性程序執行順序符合預期as-if-serial 語義 (單線程);happens-before 規則 (多線程)volatile、synchronized、final、Lock

核心洞察:單線程內表現為有序 (as-if-serial);多線程觀察彼此則表現為無序 (指令重排、緩存延遲)。JMM 通過 happens-before 建立跨線程的有序性承諾。

六、Happens-Before 八大法則

若操作 A happens-before 操作 B,則 A 的影響 (內存寫入、消息發送、方法調用等) 對 B 可見。

法則規則描述典型場景
1. 程序次序規則單線程內,按控制流順序 (非代碼行順序,含分支/循環),前面操作 HB 後面操作單線程邏輯推理基礎
2. 管程鎖定規則unlock 操作 HB 後續對同一鎖的 lock 操作synchronized/lock 保護的臨界區互斥與內存同步
3. volatile 變量規則對 volatile 寫操作 HB 後續對同一變量的讀操作狀態標誌位、雙重檢查鎖單例
4. 線程啟動規則Thread.start() HB 線程內所有操作主線程初始化數據,子線程可見
5. 線程終止規則線程內所有操作 HB 線程終止檢測 (Thread.join()/isAlive())主線程等待子線程結果
6. 線程中斷規則interrupt() 調用 HB 被中斷線程檢測到中斷 (interrupted()/isInterrupted())優雅停止線程
7. 對象終結規則對象構造函數執行結束 HB finalize() 方法開始對象銷毀前清理
8. 傳遞性A HB B 且 B HB C → A HB C跨多個同步動作鏈路傳遞可見性

七、實戰推理案例:雙重檢查鎖單例 (DCL)

public class Singleton {
    private volatile static Singleton instance; // 關鍵:volatile
    
    public static Singleton getInstance() {
        if (instance == null) {                    // 1. 讀取 instance (volatile read)
            synchronized (Singleton.class) {       // 2. lock
                if (instance == null) {            // 3. 讀取 instance (volatile read)
                    instance = new Singleton();    // 4. 構造對象 + 寫入 instance (volatile write)
                }
            }                                      // 5. unlock
        }
        return instance;                           // 6. 讀取 instance (volatile read)
    }
}

HB 推理鏈路

  1. 線程 A 執行 instance = new Singleton() (步驟 4),包含:分配內存、初始化對象、將引用寫入 instance (volatile write)
  2. 根據 volatile 寫 HB volatile 讀:步驟 4 的 volatile write HB 線程 B 後續的 volatile read (步驟 6)
  3. 根據 程序次序規則:對象初始化內存寫入 HB 步驟 4 的 volatile write (單線程內)
  4. 根據 傳遞性:對象初始化 HB 線程 B 的 volatile read → 線程 B 看到完全初始化的對象
  5. 若無 volatile:步驟 4 可能重排序為 (分配內存 → 寫入引用 → 初始化對象),線程 B 讀到非 null 但未初始化完成的引用 → 空指針/數據錯誤

八、總結

JMM 通過「主/工作內存抽象、八大原子操作、操作約束規則、特殊類型語義」定義了並發語義基礎;通過「原子性/可見性/有序性」三大特性刻畫並發正確性要求;通過「Happens-Before 八大法則」提供跨線程可見性與有序性的形式化推理工具。掌握 JMM 核心規範,能從理論層面證明 volatile/synchronized/final/Lock 等並發手段的正確性邊界,指導無鎖算法設計、並發 Bug 根因分析、高性能並發組件構建。建議開發者熟練運用 HB 圖推理並發代碼正確性,將並發編程從「經驗堆砌」提升到「數學證明」層級。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved