Java 并发编程:JUC 包中原子操作类的原理和用法
JUC(java.util.concurrent)包中的原子操作类(AtomicXXX)是 Java 并发编程中最基础、最核心的工具之一。它们提供了线程安全的变量读写操作,且性能远高于使用 synchronized 锁。
下面从原理 → 核心实现 → 常用原子类 → 使用场景 → 源码级细节全面讲解。
一、原子类家族全览(2025–2026 主流)
| 原子类 | 底层类型 | 主要用途 | 是否支持 CAS + ABA 解决 |
|---|---|---|---|
| AtomicInteger | int | 整数原子操作 | 是 |
| AtomicLong | long | 长整型原子操作 | 是 |
| AtomicBoolean | boolean | 布尔原子操作 | 是 |
| AtomicReference | 任意引用 | 任意对象的原子引用 | 是 |
| AtomicStampedReference | 引用+版本戳 | 解决 ABA 问题 | 是 |
| AtomicMarkableReference | 引用+标记 | 弱化版 ABA 解决(只关心是否变过) | 是 |
| AtomicIntegerArray | int[] | 原子整数数组 | — |
| AtomicLongArray | long[] | 原子长整型数组 | — |
| AtomicReferenceArray | 引用[] | 原子引用数组 | — |
| AtomicIntegerFieldUpdater | int 字段 | 原子更新某个对象的 int 字段 | — |
| AtomicLongFieldUpdater | long 字段 | 原子更新某个对象的 long 字段 | — |
| AtomicReferenceFieldUpdater | 引用字段 | 原子更新某个对象的引用字段 | — |
最常用的是前 5 个,尤其是 AtomicInteger、AtomicLong、AtomicReference。
二、核心原理:CAS + Unsafe + volatile
原子类的底层实现全部依赖以下三点:
- CAS(Compare And Swap)
比较并交换,是现代 CPU 提供的原子指令(cmpxchg) - Unsafe 类
通过 sun.misc.Unsafe(或 jdk.internal.misc.Unsafe)直接操作内存,实现 CAS - volatile 修饰 value 字段
保证可见性(内存屏障 + 禁止指令重排序)
以 AtomicInteger 为例的核心源码结构(简化版):
public class AtomicInteger extends Number implements java.io.Serializable {
private static final long serialVersionUID = 6214790243416807050L;
// value 使用 volatile 保证可见性
private volatile int value;
// Unsafe 实例
private static final Unsafe unsafe = Unsafe.getUnsafe();
// value 在对象内存中的偏移量
private static final long valueOffset;
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
// CAS 更新核心方法
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
// 自增并返回旧值
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
// 自增并返回新值
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
// ... 其他方法类似
}
关键点:
compareAndSet是最基础的 CAS 操作- 所有复合操作(如
getAndSet、getAndAdd、incrementAndGet)都是基于循环 CAS 实现的
三、CAS 的经典实现流程(无限重试)
public final int incrementAndGet() {
int prev, next;
do {
prev = get(); // 读取当前值(volatile 保证可见)
next = prev + 1;
} while (!compareAndSet(prev, next)); // CAS 失败则重试
return next;
}
CAS 的优点:
- 无锁(lock-free),避免线程阻塞和上下文切换
- 高并发下性能优于 synchronized(早期版本)
CAS 的缺点:
- ABA 问题(最著名)
- 循环次数多时 CPU 开销大(自旋)
- 只能保证单个变量的原子性(复合操作需要额外手段)
四、ABA 问题及解决方案
ABA 问题示例:
线程1:A → B → A(中间被改过)
线程2:看到 A,以为没变 → CAS 成功,但其实中间发生了变化
解决方案:
- AtomicStampedReference(推荐)
AtomicStampedReference<String> ref = new AtomicStampedReference<>("A", 0);
boolean success = ref.compareAndSet(
"A", // 期望引用
"C", // 更新为
0, // 期望版本戳
1 // 新版本戳
);
版本戳(stamp)每次修改都递增,解决了 ABA。
- AtomicMarkableReference
只关心是否被改过(boolean 标记),适用于“一次性”场景(如对象是否被回收)。
五、常用原子类的实战用法
1. 计数器(最经典)
private final AtomicLong requestCounter = new AtomicLong(0);
public void processRequest() {
long count = requestCounter.incrementAndGet();
// ...
}
2. 原子更新对象引用
private final AtomicReference<Node> head = new AtomicReference<>(null);
public void push(Node newNode) {
Node oldHead;
do {
oldHead = head.get();
newNode.next = oldHead;
} while (!head.compareAndSet(oldHead, newNode));
}
3. 解决 ABA(带版本)
AtomicStampedReference<Node> head = new AtomicStampedReference<>(null, 0);
public void push(Node newNode) {
int[] stampHolder = {0};
Node oldHead;
int stamp;
do {
oldHead = head.get(stampHolder);
stamp = stampHolder[0];
newNode.next = oldHead;
} while (!head.compareAndSet(oldHead, newNode, stamp, stamp + 1));
}
4. FieldUpdater(无侵入更新对象字段)
private static final AtomicIntegerFieldUpdater<Person> ageUpdater =
AtomicIntegerFieldUpdater.newUpdater(Person.class, "age");
public void birthday(Person p) {
ageUpdater.incrementAndGet(p);
}
六、原子类 vs synchronized vs Lock 性能对比(大致趋势)
| 并发量 | synchronized | ReentrantLock | AtomicXXX(CAS) |
|---|---|---|---|
| 低并发 | 较好 | 一般 | 最好 |
| 中等并发 | 一般 | 较好 | 很好 |
| 高并发 | 较差 | 一般 | 最好(无锁) |
| 非常高并发 | 差 | 一般 | 可能自旋开销大 |
现代建议:
- 简单计数、标志位 → 优先 AtomicXXX
- 需要保护代码块 → synchronized / ReentrantLock
- 极致性能 + 复杂逻辑 → LongAdder / Striped / Concurrent 集合
七、总结与一句话口诀
原子类核心:volatile + CAS + Unsafe
最底层保障:无锁、可见、原子
最常用场景:计数器、标志位、引用更新、无锁数据结构基础
口诀:
“读写可见靠 volatile,原子更新靠 CAS,
ABA 怕了用 Stamp,FieldUpdater 无侵入,
计数高并发别 synchronized,Atomic 家族最靠谱。”
如果你想继续深入某个原子类的源码细节、LongAdder vs AtomicLong 对比、无锁队列/栈的实现、AtomicXXX 在高并发场景的真实压测等,随时告诉我,我可以继续展开。