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

樂觀鎖與悲觀鎖:並發控制兩大核心策略深度對比

     編輯:Java 程式設計入門

核心理念對比

維度悲觀鎖樂觀鎖
假設衝突常發生,必須預防衝突罕見,先執行再檢測
機制操作前加鎖(互斥)無鎖,CAS/版本號檢測衝突
衝突處理阻塞等待鎖釋放重試/拋出異常/回滾
適用場景寫多讀少、高衝突、強一致性要求讀多寫少、低衝突、高吞吐優先
典型實現synchronized, ReentrantLock, 數據庫行鎖AtomicInteger, LongAdder, 數據庫版本號

悲觀鎖:Java 內置實現

// 1. synchronized (對象鎖/類鎖)
public synchronized void transfer(Account from, Account to, int amt) { ... }

// 2. ReentrantLock (顯式鎖,功能更強)
Lock lock = new ReentrantLock();
lock.lock();
try { /* 臨界區 */ } finally { lock.unlock(); }

缺點:線程阻塞/喚醒開銷大(用戶態↔內核態切換)、死鎖風險、鎖競爭導致吞吐下降、優先級反轉。

樂觀鎖:CAS 原理與 Java 實現

Compare-And-Swap (CAS) 三元組

CAS(V, A, B):內存值 V、預期值 A、新值 B。原子操作:若 V == A 則 V = B 返回 true,否則不修改返回 false。

  • 硬件指令保證原子性(CPU LOCK CMPXCHG)。
  • 非阻塞:失敗線程不掛起,可自旋重試或放棄。

Java 原子類家族

// 基本類型原子更新
AtomicInteger count = new AtomicInteger(0);
count.incrementAndGet(); // 原子 i++
count.compareAndSet(5, 10); // 手動 CAS

// 長整型高併發優化
LongAdder adder = new LongAdder(); // 內部分段,減少競爭
adder.increment();
long sum = adder.sum();

// 引用類型原子更新
AtomicReference ref = new AtomicReference<>("init");
ref.compareAndSet("init", "updated");

// 數組元素原子更新
AtomicIntegerArray arr = new AtomicIntegerArray(10);
arr.getAndIncrement(0);

ABA 問題與解決

線程 1 讀到 A,線程 2 改 A→B→A,線程 1 CAS 成功但實際數據已變。解決:AtomicStampedReference (版本戳) 或 AtomicMarkableReference (布爾標記)。

數據庫層面的樂觀鎖

-- 表增加 version 欄位
UPDATE account SET balance = balance - 100, version = version + 1
WHERE id = 1 AND version = 5; -- 版本匹配才更新
-- affected rows = 0 表示衝突,應用層重試

選型決策樹

  1. 是否高併發寫入? → 是 → 悲觀鎖 / 分布式鎖。
  2. 讀多寫少、衝突率低? → 樂觀鎖 (Atomic* / 版本號)。
  3. 需要事務特性(回滾)? → 悲觀鎖 (數據庫行鎖) 或 分布式事務。
  4. 長事務/遠程調用? → 避免持有鎖,用樂觀鎖/補償機制。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved