- Java 原子类详解
- 一、基本类型原子类
- 二、数组原子类
- 三、引用原子类
- 四、字段更新器
- 五、累加器(JDK 8+)
- 六、核心对比
- AtomicLong vs LongAdder
- 选型速查
- 七、底层原理简述
- 八、注意事项
Java 原子类详解
所有类位于 java.util.concurrent.atomic 包下。
一、基本类型原子类
| 类名 |
说明 |
AtomicInteger |
原子 int |
AtomicLong |
原子 long |
AtomicBoolean |
原子 boolean |
AtomicInteger counter = new AtomicInteger(0);counter.incrementAndGet(); // ++i
counter.getAndIncrement(); // i++
counter.decrementAndGet(); // --i
counter.getAndDecrement(); // i--
counter.addAndGet(5); // += 5
counter.getAndAdd(5); // 返回旧值,再 += 5
counter.compareAndSet(0, 10); // CAS:期望0则设为10,返回是否成功
counter.getAndUpdate(x -> x * 2); // 原子计算,返回旧值
counter.updateAndGet(x -> x * 2); // 原子计算,返回新值
二、数组原子类
| 类名 |
说明 |
AtomicIntegerArray |
原子 int 数组 |
AtomicLongArray |
原子 long 数组 |
AtomicReferenceArray<V> |
原子引用数组 |
AtomicIntegerArray array = new AtomicIntegerArray(10);
array.incrementAndGet(0); // 索引0位置原子+1
array.compareAndSet(0, 1, 5); // 索引0期望1则设为5
三、引用原子类
| 类名 |
说明 |
AtomicReference<V> |
原子引用 |
AtomicStampedReference<V> |
带版本号,解决 ABA 问题 |
AtomicMarkableReference<V> |
带布尔标记 |
// AtomicReference — 最常见,CAS 更新对象
AtomicReference<User> ref = new AtomicReference<>(new User("张三"));
ref.compareAndSet(oldUser, newUser); // CAS 更新对象引用
ref.updateAndGet(u -> new User(u.getName() + "_new"));// AtomicStampedReference — 解决 ABA 问题
// 场景:线程A读到值X,线程B把X改成Y又改回X,线程A CAS 时发现还是 X 就更新了,但中间已经变过
AtomicStampedReference<Integer> ref2 = new AtomicStampedReference<>(100, 0);
int stamp = ref2.getStamp();
ref2.compareAndSet(100, 200, stamp, stamp + 1); // 版本号也参与 CAS// AtomicMarkableReference — 带布尔标记(如"是否已删除")
AtomicMarkableReference<Node> ref3 = new AtomicMarkableReference<>(node, false);
ref3.compareAndSet(oldNode, newNode, false, true); // 标记为 true
ABA 问题图示
线程A:读到值 X ──────────────────── CAS(X → Z) 成功,但不知道中间变过
线程B: X → Y → XAtomicStampedReference 通过版本号解决:
线程A:读到 (X, stamp=1) ────────── CAS 失败,因为 stamp 已变成 3
线程B: (X,1) → (Y,2) → (X,3)
四、字段更新器
原子更新某个类的 volatile 字段,适用于大量对象实例的场景,节省内存。
| 类名 |
说明 |
AtomicIntegerFieldUpdater<T> |
更新对象 int 字段 |
AtomicLongFieldUpdater<T> |
更新对象 long 字段 |
AtomicReferenceFieldUpdater<T,V> |
更新对象引用字段 |
class Player {volatile int score; // 必须是 volatile 且非 private(或通过反射可访问)volatile long timestamp;
}// 创建更新器
AtomicIntegerFieldUpdater<Player> updater =AtomicIntegerFieldUpdater.newUpdater(Player.class, "score");Player p = new Player();
updater.incrementAndGet(p); // 原子更新 p.score
updater.compareAndSet(p, 0, 100);
适用场景: 有成千上万个 Player 对象,如果每个都包一个 AtomicInteger,内存开销大。用 FieldUpdater 只需一份 Updater 实例。
限制:
- 字段必须是
volatile
- 字段不能是
private(除非调用者能访问)
- 字段不能是
static
五、累加器(JDK 8+)
高并发写入场景下吞吐量远超 AtomicLong。
| 类名 |
说明 |
LongAdder |
高并发 long 累加 |
DoubleAdder |
高并发 double 累加 |
LongAccumulator |
自定义累加逻辑 |
DoubleAccumulator |
自定义 double 累加逻辑 |
// LongAdder — 高并发计数首选(如 QPS 统计、请求量计数)
LongAdder adder = new LongAdder();
adder.increment(); // +1
adder.add(10); // +10
adder.decrement(); // -1
long sum = adder.sum(); // 求和(注意:非强一致性快照,高并发下可能有偏差)
adder.reset(); // 重置为0
adder.sumThenReset(); // 求和并重置// LongAccumulator — 自定义运算(不限于加法)
// 参数:(运算函数, 初始值)
LongAccumulator maxAcc = new LongAccumulator(Long::max, Long.MIN_VALUE);
maxAcc.accumulate(100);
maxAcc.accumulate(200);
maxAcc.get(); // 200LongAccumulator minAcc = new LongAccumulator(Long::min, Long.MAX_VALUE);
minAcc.accumulate(5);
minAcc.accumulate(3);
minAcc.get(); // 3// 也可以做乘法累乘
LongAccumulator product = new LongAccumulator((a, b) -> a * b, 1);
product.accumulate(2);
product.accumulate(3);
product.accumulate(4);
product.get(); // 24
六、核心对比
AtomicLong vs LongAdder
| 维度 |
AtomicLong |
LongAdder |
| 实现原理 |
CAS 自旋,单热点值 |
分段累加(Cell 数组),分散竞争 |
| 低并发 |
性能相当 |
性能相当 |
| 高并发 |
CAS 失败频繁,CPU 自旋浪费 |
吞吐量远超 AtomicLong |
| 内存占用 |
8 字节 |
更多(Cell 数组 + 填充) |
| 瞬时值准确性 |
精确 |
近似(sum 时合并 Cell) |
| 适用场景 |
低并发、需要精确瞬时值、CAS 状态控制 |
高并发统计计数(QPS、请求量) |
选型速查
| 场景 |
推荐 |
| 高并发计数/统计 |
LongAdder |
| 需要精确瞬时值 |
AtomicLong |
| 需要 CAS 精确控制状态(标志位、状态机) |
AtomicInteger / AtomicLong |
| CAS 更新对象引用 |
AtomicReference |
| 需要解决 ABA 问题 |
AtomicStampedReference |
| 大量对象实例,节省内存 |
AtomicIntegerFieldUpdater / AtomicLongFieldUpdater |
| 自定义累加逻辑(max/min/乘积等) |
LongAccumulator |
七、底层原理简述
所有原子类的核心是 CAS(Compare And Swap):
CAS(内存地址, 期望值, 新值):如果 内存值 == 期望值 → 更新为新值,返回 true否则 → 不更新,返回 false
- CAS 是 CPU 级别的原子指令(
cmpxchg)
- JDK 通过
Unsafe.compareAndSwapXxx 或 VarHandle 调用
- CAS 失败时通常自旋重试(自旋锁思想)
LongAdder 进一步优化:热点分散到多个 Cell,减少 CAS 竞争
八、注意事项
LongAdder.sum() 不是强一致性的,高并发写入时读到的可能是近似值
AtomicStampedReference 的 stamp 是 int,会溢出回绕,但概率极低
- FieldUpdater 的字段必须是
volatile,否则无法保证可见性
- 原子类只保证单个操作的原子性,多个原子操作组合不原子:
// ❌ 这不是原子的
if (counter.get() < 10) {counter.incrementAndGet(); // 检查和操作之间有间隙
}
// ✅ 应该用 compareAndSet
- JDK 9+ 底层改为 VarHandle,性能和灵活性更好,但 API 不变