Java 原子类详解

Java 原子类详解

目录
  • Java 原子类详解
    • 一、基本类型原子类
    • 二、数组原子类
    • 三、引用原子类
      • ABA 问题图示
    • 四、字段更新器
    • 五、累加器(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.compareAndSwapXxxVarHandle 调用
  • CAS 失败时通常自旋重试(自旋锁思想)
  • LongAdder 进一步优化:热点分散到多个 Cell,减少 CAS 竞争

八、注意事项

  1. LongAdder.sum() 不是强一致性的,高并发写入时读到的可能是近似值
  2. AtomicStampedReference 的 stamp 是 int,会溢出回绕,但概率极低
  3. FieldUpdater 的字段必须是 volatile,否则无法保证可见性
  4. 原子类只保证单个操作的原子性,多个原子操作组合不原子:
    // ❌ 这不是原子的
    if (counter.get() < 10) {counter.incrementAndGet();  // 检查和操作之间有间隙
    }
    // ✅ 应该用 compareAndSet
    
  5. JDK 9+ 底层改为 VarHandle,性能和灵活性更好,但 API 不变