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

Java 並發編程:各類鎖機制核心概念與對比分析

     編輯:Java 相關知識

鎖是並發編程中協調共享資源訪問的核心手段。本文系統梳理 Java 體系中共享鎖/排他鎖、悲觀鎖/樂觀鎖、公平鎖/非公平鎖、可重入鎖、自旋鎖、偏向鎖/輕量級鎖/重量級鎖等核心概念,並對比其適用場景與實現原理。

一、按數據庫理論分類:共享鎖 vs 排他鎖

鎖類型別名兼容性操作權限典型場景
共享鎖 (S鎖)讀鎖S-S 兼容,S-X 互斥只能讀,不能改SELECT ... LOCK IN SHARE MODE
排他鎖 (X鎖)寫鎖X 與任何鎖互斥可讀可改SELECT ... FOR UPDATE、UPDATE/DELETE

意向鎖 (IS/IX):表級鎖,標明事務意圖獲取行級 S/X 鎖,避免全表掃描檢查行鎖衝突。

二、按並發策略分類:悲觀鎖 vs 樂觀鎖

維度悲觀鎖樂觀鎖
核心假設衝突常見,先獲取鎖再操作衝突罕見,操作後驗證衝突
實現方式synchronized、Lock、數據庫行鎖CAS(Compare-And-Swap)、版本號/時間戳
優點強一致性、簡單直接無阻塞、高並發吞吐、無死鎖
缺點阻塞等待、死鎖風險、性能差ABA 問題、衝突重試開銷、只能保證單變量原子性
適用場景寫多讀少、強一致性要求、臨界區耗時長讀多寫少、衝突率低、CAS 硬件支持

2.1 Java 樂觀鎖實現:Atomic 類與 LongAdder


// CAS 核心:compareAndSet(expected, update)
// 底層依賴 Unsafe.compareAndSwapInt/Long/Object + volatile
AtomicInteger count = new AtomicInteger(0);
count.incrementAndGet(); // 線程安全計數

// 高並發計數器:LongAdder 分段累加,最後求和
LongAdder adder = new LongAdder();
adder.increment();
long sum = adder.sum();

三、按線程調度分類:公平鎖 vs 非公平鎖

  • 公平鎖:嚴格按請求順序獲取鎖 (FIFO),ReentrantLock(true)。優點:無飢餓;缺點:吞吐率低,線程切換開銷大
  • 非公平鎖:搶佔模式,新請求嘗試插隊獲取鎖,synchronized、ReentrantLock() 默認。優點:吞吐率高;缺點:可能飢餓

選擇建議:默認非公平鎖;只有明確公平性需求(如嚴格順序處理)才用公平鎖。

四、按可重入性分類:可重入鎖

  • 定義:同一線程可多次獲取同一把鎖,計數器 +1,釋放時 -1,歸零才真正釋放
  • Java 實現:synchronized、ReentrantLock 均為可重入鎖
  • 作用:避免同一線程調用遞歸方法或調用另一個同步方法時死鎖

五、JVM 鎖升級機制:偏向鎖 → 輕量級鎖 → 重量級鎖

鎖狀態觸發條件核心機制適用場景Mark Word 狀態
無鎖對象創建無同步單線程訪問01 (無鎖標識)
偏向鎖單線程反復訪問CAS 設置線程 ID 到 Mark Word,後續無需 CAS無競爭、單線程高頻101 (偏向標識) + ThreadID
輕量級鎖多線程交替訪問CAS 將 Mark Word 指向棧中 Lock Record,自旋等待低競爭、短臨界區00 (輕量級標識) + Lock Record 指針
重量級鎖高競爭/自旋超時ObjectMonitor 監視器,OS 互斥量,線程阻塞高競爭、長臨界區10 (重量級標識) + Monitor 指針

關鍵參數:-XX:+UseBiasedLocking (默認開啟)、-XX:BiasedLockingStartupDelay=4000、-XX:PreBlockSpin=10 (自旋次數)。

六、Linux 內核自旋鎖

// 內核自旋鎖簡化模型
spinlock_t lock = SPIN_LOCK_UNLOCKED;

void spin_lock(spinlock_t *lock) {
    while (test_and_set_bit(0, &lock->lock)) {
        cpu_relax(); // PAUSE 指令,降低總線壓力
    }
    // 獲得鎖,進入臨界區
}

void spin_unlock(spinlock_t *lock) {
    clear_bit(0, &lock->lock);
}
  • 特點:忙等待(自旋),不睡眠,不引發上下文切換
  • 適用:極短臨界區、中斷上下文、多核系統
  • 風險:長時間持有導致 CPU 空轉、優先級反轉

七、Java 顯式鎖 Lock 體系核心

接口/類核心特性關鍵方法
Lock顯式獲取/釋放、可中斷、超時、公平性選項lock(), unlock(), tryLock(), lockInterruptibly()
ReentrantLock可重入、支持 Condition、公平/非公平繼承 Lock,newCondition()
ReadWriteLock讀寫分離、多讀單寫readLock(), writeLock()
ReentrantReadWriteLock可重入讀寫鎖、支持降級(寫→讀)實現 ReadWriteLock
StampedLock樂觀讀鎖、不可重入、性能更強tryOptimisticRead(), validate(), readLock(), writeLock()

八、死鎖預防與排查

  1. 避免嵌套鎖:按固定順序獲取多把鎖
  2. 使用 tryLock 超時:避免無限等待
  3. 縮小鎖範圍:只保護必要代碼
  4. 排查工具:jstack 線程導出分析 BLOCKED 狀態、Arthas thread -b、JConsole/JVisualVM 死鎖檢測
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved