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

深入理解Java內存模型(五):鎖的happens-before關係、內存語義與ReentrantLock源碼級實現剖析

     編輯:Java 相關知識

鎖釋放-獲取建立的 happens-before 關係

class MonitorExample {
    int a = 0;
    public synchronized void writer() { a++; } // 1→2→3
    public synchronized void reader()  { int i = a; } // 4→5→6
}

happens-before 鏈路:

  1. 程序順序:1→2→3、4→5→6
  2. 監視器鎖規則:3(釋放鎖)→4(獲取鎖)
  3. 傳遞性:2→5

happens-before圖示

含義:線程 A 釋放鎖前對共享變量的修改,線程 B 獲取同一鎖後立即可見。

鎖的內存語義:釋放≈volatile寫,獲取≈volatile讀

  • 釋放鎖:將本地內存共享變量刷新到主內存 釋放鎖狀態
  • 獲取鎖:將本地內存置無效,從主內存重讀共享變量 獲取鎖狀態

本質:線程 A 通過主內存向線程 B 發送消息(共享變量修改)。

ReentrantLock 內存語義源碼級實現

公平鎖

  • 獲取鎖:tryAcquire 首先 讀 volatile state
  • 釋放鎖:tryRelease 最後 寫 volatile state
  • 利用 volatile 讀-寫 happens-before 傳遞可見性

非公平鎖

  • 釋放同公平鎖:寫 volatile state
  • 獲取鎖:compareAndSetState (CAS) —— 同時具備 volatile 讀和寫語義

CAS 為何同時具備 volatile 讀/寫語義

編譯器視角

CAS 前後不能重排序任何內存操作(結合 volatile 讀後不重排、寫前不重排規則)。

處理器視角

OpenJDK x86 實現:lock cmpxchg 指令

LOCK_IF_MP(mp) cmpxchg dword ptr [edx], ecx

lock 前綴三大效果:

  1. 原子性:多核下緩存鎖定或總線鎖定
  2. 禁止重排:與前後讀寫指令不重排
  3. 刷新寫緩衝區:將數據刷至內存

第 2、3 點完美實現 volatile 讀+寫語義。

Java 線程通信四種模式

模式寫端讀端
volatile 寫-讀volatile writevolatile read
volatile 寫-CASvolatile writeCAS update
CAS-CASCAS updateCAS update
CAS-讀CAS updatevolatile read

concurrent 包實現基石模式

  1. 聲明共享變量為 volatile
  2. 使用 CAS 原子條件更新 實現同步
  3. 配合 volatile 讀/寫與 CAS 語義實現線程通信

concurrent包實現示意

AQS、非阻塞數據結構、原子變量類均遵循此模式,高層組件依賴基礎類構建。

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