原子操作是併發編程的基石。本文從 CPU 硬體指令(總線鎖/緩存鎖)、JVM 內部實現(Unsafe + CAS)、Java 並發包應用(AtomicInteger、AtomicReference),到 CAS 三大經典問題(ABA、自旋開銷、單變量限制)及鎖機制關係,全鏈路剖析原子操作實現原理。

LOCK# 信號,佔用總線,阻塞其他 CPU 內存訪問。LOCK# 信號。CPU 提供帶 LOCK 前綴的指令自動使用上述機制:
BTS、BTR、BTCXADD、CMPXCHGADD、OR 等核心思路:while(true) { 讀舊值; 計算新值; if (CAS(舊值, 新值)) break; }
private void safeCount() {
for (;;) {
int i = atomicI.get();
boolean suc = atomicI.compareAndSet(i, ++i);
if (suc) break;
}
}
AtomicInteger.compareAndSet 最終調用 Unsafe.compareAndSwapInt → JVM 內部 CMPXCHG 指令。
| 問題 | 描述 | 解決方案 |
|---|---|---|
| ABA 問題 | 值 A→B→A,CAS 以為未變 | 版本號戳:AtomicStampedReference,compareAndSet(ref, newRef, stamp, newStamp) |
| 自旋開銷大 | 長時間 CAS 失敗佔用 CPU | JVM 支援 pause 指令(延遲流水線、避免內存順序衝突刷新管線) |
| 只能保證單變量 | 多變量邀請無法原子 | 1. 用鎖 2. 合併為一個對象用 AtomicReference 3. JDK 1.5+ AtomicReference 封裝多字段 |
public boolean compareAndSet(
V expectedReference, V newReference,
int expectedStamp, int newStamp) { ... }
每次更新同時遞增 stamp,A-B-A 變為 1A-2B-3A,CAS 檢測到 stamp 變化而失敗。
synchronized(偏向鎖除外)進入/退出同步塊時,均使用循環 CAS 獲取/釋放鎖標記。public class Counter {
private AtomicInteger atomicI = new AtomicInteger(0);
private int i = 0;
public static void main(String[] args) throws InterruptedException {
Counter cas = new Counter();
List ts = new ArrayList<>(600);
long start = System.currentTimeMillis();
for (int j = 0; j < 100; j++) {
Thread t = new Thread(() -> {
for (int k = 0; k < 10000; k++) {
cas.count(); // 非線程安全
cas.safeCount(); // CAS 線程安全
}
});
ts.add(t);
}
ts.forEach(Thread::start);
ts.forEach(t -> { try { t.join(); } catch (InterruptedException e) {} });
System.out.println("非安全計數: " + cas.i); // < 1,000,000
System.out.println("CAS 安全計數: " + cas.atomicI.get()); // = 1,000,000
System.out.println("耗時: " + (System.currentTimeMillis() - start) + "ms");
}
private void safeCount() { /* 上述 CAS 循環 */ }
private void count() { i++; }
}
Unsafe.CAS 直接映射 CMPXCHG 指令,Java 並發包全部構建於此。讀-算-CAS 循環,無鎖、高併發、但需處理 ABA、自旋、單變量限制。AtomicLong/Integer/BooleanAtomicReferenceAtomicStampedReference / AtomicMarkableReferencesynchronized / ReentrantLock / STM(如 Multiverse)LongAdder 熱點分離)。理解原子操作從 CPU 指令到 Java API 的完整鏈路,是寫出高性能、正確併發代碼的前提。下次使用 AtomicInteger 時,腦海中應浮現 CMPXCHG、緩存行、MESI、自旋循環這條完整鏈路。