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

Java 非阻塞同步機制:CAS 原理、原子變量與性能對比

     編輯:Java 相關知識

非阻塞算法簡介

非阻塞算法屬於並發算法,不使用鎖,而是依賴硬件原生原子指令(如 CAS)實現線程協作。優勢:避免死鎖、優先級反轉;高併發下吞吐率通常優於鎖。缺點:實現極其困難,需處理 ABA 問題、指令重排等。

悲觀鎖 vs 樂觀鎖

維度悲觀鎖樂觀鎖 (CAS)
假設衝突經常發生,必須加鎖衝突罕見,先嘗試更新,失敗再重試
實現synchronized, ReentrantLockCAS 指令 (Unsafe.compareAndSwapInt)
優點簡單、強一致性無阻塞、無死鎖、性能隨併發度增長
缺點上下文切換開銷、死鎖風險高衝突下重試消耗 CPU、ABA 問題

CAS (Compare-And-Swap) 原理

三個操作數:內存值 V、預期值 A、新值 B。
原子操作:if (V == A) V = B; return old V;

典型模式:

  1. 讀取 V 為 A。
  2. 基於 A 計算新值 B。
  3. CAS(V, A, B):若期間 V 未被修改則更新成功,否則重試。

模擬 CAS 實現

public class SimulatedCAS {
    private int value;
    public synchronized int getValue() { return value; }
    public synchronized int compareAndSwap(int expected, int newValue) {
        int old = value;
        if (value == expected) value = newValue;
        return old;
    }
}

public class CasCounter {
    private SimulatedCAS value = new SimulatedCAS();
    public int getValue() { return value.getValue(); }
    public int increment() {
        int old = value.getValue();
        while (value.compareAndSwap(old, old + 1) != old)
            old = value.getValue();
        return old + 1;
    }
}

Java 原子變量類體系

JDK 5.0+ java.util.concurrent.atomic 包提供 12 個原子類,四大類:

類別代表類適用場景
標量AtomicInteger, AtomicLong, AtomicBoolean, AtomicReference單一變量原子更新
字段更新器AtomicIntegerFieldUpdater, AtomicLongFieldUpdater, AtomicReferenceFieldUpdater非原子字段原子化更新
數組AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray數組元素原子更新
復合AtomicMarkableReference, AtomicStampedReference解決 ABA 問題(帶版本戳/標記)

常用原子類方法示例 (AtomicInteger)

AtomicInteger cnt = new AtomicInteger(0);
cnt.get();                    // 獲取值
cnt.set(10);                  // 設置值
cnt.getAndSet(20);            // 設置並返回舊值
cnt.getAndIncrement();        // i++ 返回舊值
cnt.incrementAndGet();        // ++i 返回新值
cnt.getAndAdd(5);             // +=5 返回舊值
cnt.compareAndSet(10, 15);    // CAS 期望 10 更新為 15

性能對比:鎖 vs 原子變量

  • 低/中併發:原子變量擴展性極佳,性能遠超鎖。
  • 高併發:鎖通過阻塞減少 CPU 空轉,性能反超原子變量(自旋重試消耗大)。
  • 真實場景:多數業務屬低/中併發,原子變量整體表現更優。

ABA 問題與解決

場景:線程 1 讀取 V=A,線程 2 將 V 改為 B 再改回 A,線程 1 CAS 成功但實際語義已變。
解決:使用 AtomicStampedReference(帶整數戳記)或 AtomicMarkableReference(布爾標記)。

AtomicStampedReference<Integer> ref = new AtomicStampedReference<>(100, 0);
// 更新時檢查戳記
ref.compareAndSet(100, 200, stamp, stamp+1);

最佳實踐建議

  1. 簡單計數器、標誌位、引用更新 → AtomicInteger/Long/Boolean/Reference。
  2. 需對對象多字段原子更新 → 封裝為不可變對象 + AtomicReference。
  3. 高併發計數 → LongAdder (JDK 8) 分段累加,性能優於 AtomicLong。
  4. 避免在循環中長時間自旋 CAS,考慮鎖或 Thread.onSpinWait() (JDK 9+)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved