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

JUC 原子類全景圖:四大類型、核心原理與實戰選型指南

     編輯:Java 相關知識

在高併發編程中,傳統的 synchronized 或 ReentrantLock 屬於重量級鎖,上下文切換開銷大。Java 並發包(JUC)提供的 原子類 基於 CAS(Compare-And-Swap)無鎖算法,實現了細粒度的無阻塞並發控制,是構建高性能並發應用的利器。java.util.concurrent.atomic 包下的原子類按操作數據類型劃分為四大類,共 17 個核心類。

四大原子類家族圖譜

類別 核心類 適用場景 典型用例
基本類型 AtomicInteger
AtomicLong
AtomicBoolean
單個基本類型變量的原子更新 計數器、序列生成器、開關標誌
數組類型 AtomicIntegerArray
AtomicLongArray
AtomicReferenceArray
數組元素的原子更新 並發安全的數組計數、引用數組更新
引用類型 AtomicReference<V>
AtomicStampedReference<V>
AtomicMarkableReference<V>
對象引用的原子更新,解決 ABA 問題 無鎖數據結構、版本號控制、標記位控制
字段更新器 AtomicIntegerFieldUpdater
AtomicLongFieldUpdater
AtomicReferenceFieldUpdater
基於反射對指定對象的 volatile 字段原子更新 無法修改類源碼時,對現有對象字段原子操作

核心原理:CAS 與 volatile 的雙重保障

所有原子類的核心實現均依賴 CAS(Compare-And-Swap) 指令,這是一條 CPU 級原子指令,語義為:

「若內存值等於預期值,則更新為新值;否則不更新,返回當前內存值。」

在 Java 中通過 sun.misc.Unsafe 的 compareAndSwapInt/Long/Object 方法調用。配合 volatile 關鍵字保證內存可見性,實現無鎖並發:

  • 原子性:CAS 硬件指令保證讀-改-寫不可分割
  • 可見性:volatile 變量修改對所有線程立即可見
  • 無阻塞:失敗時自旋重試,無線程掛起/喚醒開銷

深度解析三大引用類型原子類

AtomicReference<V>:基礎引用原子更新

AtomicReference<User> userRef = new AtomicReference<>();
// 原子性地更新引用
userRef.compareAndSet(oldUser, newUser);

AtomicStampedReference<V>:版本號解決 ABA 問題

ABA 問題:線程 1 讀取值 A,線程 2 將 A→B→A,線程 1 CAS 成功但實際數據已變更。AtomicStampedReference 通過 整型版本號 標記每次變更:

AtomicStampedReference<Integer> ref = new AtomicStampedReference<>(100, 0);
// 更新時需提供舊值、新值、舊版本號、新版本號
ref.compareAndSet(100, 200, stamp, stamp + 1);

AtomicMarkableReference<V>:布爾標記輕量級 ABA 防護

當只需關心「是否被修改過」而不關心具體版本時,使用單個 boolean 標記,空間開銷更小:

AtomicMarkableReference<Node> nodeRef = new AtomicMarkableReference<>(head, false);
nodeRef.compareAndSet(head, newHead, false, true);

字段更新器:無侵入式原子化現有對象

當你無法修改第三方類源碼(無法將字段改為原子類),但需要對其 volatile 字段進行原子操作時,字段更新器是唯一選擇:

public class Counter {
    public volatile int count; // 必須是 volatile
}

// 靜態工廠方法創建更新器
AtomicIntegerFieldUpdater<Counter> updater = 
    AtomicIntegerFieldUpdater.newUpdater(Counter.class, "count");

Counter counter = new Counter();
updater.incrementAndGet(counter); // 原子增 1

限制:僅支持 volatile 非靜態字段;基於反射,性能略低於直接使用原子類。

選型決策樹

  1. 操作單個基本類型變量?→ AtomicInteger/Long/Boolean
  2. 操作數組元素?→ Atomic*Array
  3. 操作對象引用?
    • 需防 ABA(版本號)?→ AtomicStampedReference
    • 需防 ABA(標記位)?→ AtomicMarkableReference
    • 一般場景?→ AtomicReference
  4. 無法修改類源碼,需原子化現有對象字段?→ Atomic*FieldUpdater

性能與避坑指南

  • 高併發下自旋開銷:CAS 失敗自旋消耗 CPU,極高併發考慮 LongAdder(分段計數)或鎖
  • ABA 問題:引用類型更新務必評估 ABA 風險,選用帶版本號/標記的類
  • volatile 不可少:字段更新器要求目標字段必須是 volatile
  • 複合操作非原子:get() 後 set() 非原子,必須用 compareAndSet() 或 updateAndGet()

JUC 原子類是無鎖並發編程的基石,掌握其四大類型特性、CAS 底層原理及 ABA 防護機制,能讓你在高併發系統設計中游刃有餘,寫出既高效又正確的並發代碼。

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