在高併發編程中,傳統的 synchronized 或 ReentrantLock 屬於重量級鎖,上下文切換開銷大。Java 並發包(JUC)提供的 原子類 基於 CAS(Compare-And-Swap)無鎖算法,實現了細粒度的無阻塞並發控制,是構建高性能並發應用的利器。java.util.concurrent.atomic 包下的原子類按操作數據類型劃分為四大類,共 17 個核心類。
| 類別 | 核心類 | 適用場景 | 典型用例 |
|---|---|---|---|
| 基本類型 | AtomicIntegerAtomicLongAtomicBoolean |
單個基本類型變量的原子更新 | 計數器、序列生成器、開關標誌 |
| 數組類型 | AtomicIntegerArrayAtomicLongArrayAtomicReferenceArray |
數組元素的原子更新 | 並發安全的數組計數、引用數組更新 |
| 引用類型 | AtomicReference<V>AtomicStampedReference<V>AtomicMarkableReference<V> |
對象引用的原子更新,解決 ABA 問題 | 無鎖數據結構、版本號控制、標記位控制 |
| 字段更新器 | AtomicIntegerFieldUpdaterAtomicLongFieldUpdaterAtomicReferenceFieldUpdater |
基於反射對指定對象的 volatile 字段原子更新 |
無法修改類源碼時,對現有對象字段原子操作 |
所有原子類的核心實現均依賴 CAS(Compare-And-Swap) 指令,這是一條 CPU 級原子指令,語義為:
「若內存值等於預期值,則更新為新值;否則不更新,返回當前內存值。」
在 Java 中通過 sun.misc.Unsafe 的 compareAndSwapInt/Long/Object 方法調用。配合 volatile 關鍵字保證內存可見性,實現無鎖並發:
AtomicReference<User> userRef = new AtomicReference<>(); // 原子性地更新引用 userRef.compareAndSet(oldUser, newUser);
ABA 問題:線程 1 讀取值 A,線程 2 將 A→B→A,線程 1 CAS 成功但實際數據已變更。AtomicStampedReference 通過 整型版本號 標記每次變更:
AtomicStampedReference<Integer> ref = new AtomicStampedReference<>(100, 0); // 更新時需提供舊值、新值、舊版本號、新版本號 ref.compareAndSet(100, 200, stamp, stamp + 1);
當只需關心「是否被修改過」而不關心具體版本時,使用單個 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 非靜態字段;基於反射,性能略低於直接使用原子類。
AtomicInteger/Long/BooleanAtomic*ArrayAtomicStampedReferenceAtomicMarkableReferenceAtomicReferenceAtomic*FieldUpdaterLongAdder(分段計數)或鎖volatileget() 後 set() 非原子,必須用 compareAndSet() 或 updateAndGet()JUC 原子類是無鎖並發編程的基石,掌握其四大類型特性、CAS 底層原理及 ABA 防護機制,能讓你在高併發系統設計中游刃有餘,寫出既高效又正確的並發代碼。