Java 并发编程:JUC 包中原子操作类的原理和用法

Java 并发编程:JUC 包中原子操作类的原理和用法

JUC(java.util.concurrent)包中的原子操作类(AtomicXXX)是 Java 并发编程中最基础、最核心的工具之一。它们提供了线程安全的变量读写操作,且性能远高于使用 synchronized 锁。

下面从原理 → 核心实现 → 常用原子类 → 使用场景 → 源码级细节全面讲解。

一、原子类家族全览(2025–2026 主流)

原子类底层类型主要用途是否支持 CAS + ABA 解决
AtomicIntegerint整数原子操作
AtomicLonglong长整型原子操作
AtomicBooleanboolean布尔原子操作
AtomicReference任意引用任意对象的原子引用
AtomicStampedReference引用+版本戳解决 ABA 问题
AtomicMarkableReference引用+标记弱化版 ABA 解决(只关心是否变过)
AtomicIntegerArrayint[]原子整数数组
AtomicLongArraylong[]原子长整型数组
AtomicReferenceArray引用[]原子引用数组
AtomicIntegerFieldUpdaterint 字段原子更新某个对象的 int 字段
AtomicLongFieldUpdaterlong 字段原子更新某个对象的 long 字段
AtomicReferenceFieldUpdater引用字段原子更新某个对象的引用字段

最常用的是前 5 个,尤其是 AtomicIntegerAtomicLongAtomicReference

二、核心原理:CAS + Unsafe + volatile

原子类的底层实现全部依赖以下三点:

  1. CAS(Compare And Swap)
    比较并交换,是现代 CPU 提供的原子指令(cmpxchg)
  2. Unsafe 类
    通过 sun.misc.Unsafe(或 jdk.internal.misc.Unsafe)直接操作内存,实现 CAS
  3. 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 操作
  • 所有复合操作(如 getAndSetgetAndAddincrementAndGet)都是基于循环 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 的缺点

  1. ABA 问题(最著名)
  2. 循环次数多时 CPU 开销大(自旋)
  3. 只能保证单个变量的原子性(复合操作需要额外手段)

四、ABA 问题及解决方案

ABA 问题示例

线程1:A → B → A(中间被改过)
线程2:看到 A,以为没变 → CAS 成功,但其实中间发生了变化

解决方案

  1. AtomicStampedReference(推荐)
AtomicStampedReference<String> ref = new AtomicStampedReference<>("A", 0);

boolean success = ref.compareAndSet(
    "A",           // 期望引用
    "C",           // 更新为
    0,             // 期望版本戳
    1              // 新版本戳
);

版本戳(stamp)每次修改都递增,解决了 ABA。

  1. 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 性能对比(大致趋势)

并发量synchronizedReentrantLockAtomicXXX(CAS)
低并发较好一般最好
中等并发一般较好很好
高并发较差一般最好(无锁)
非常高并发一般可能自旋开销大

现代建议

  • 简单计数、标志位 → 优先 AtomicXXX
  • 需要保护代码块 → synchronized / ReentrantLock
  • 极致性能 + 复杂逻辑 → LongAdder / Striped / Concurrent 集合

七、总结与一句话口诀

原子类核心volatile + CAS + Unsafe
最底层保障无锁、可见、原子
最常用场景:计数器、标志位、引用更新、无锁数据结构基础

口诀

“读写可见靠 volatile,原子更新靠 CAS,
ABA 怕了用 Stamp,FieldUpdater 无侵入,
计数高并发别 synchronized,Atomic 家族最靠谱。”

如果你想继续深入某个原子类的源码细节LongAdder vs AtomicLong 对比无锁队列/栈的实现AtomicXXX 在高并发场景的真实压测等,随时告诉我,我可以继续展开。

文章已创建 4631

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部