AtomicReference 通过 CAS 实现引用的原子更新,保证多线程下引用变更的线程安全,适用于共享对象引用的无锁更新场景,需配合自旋重试或使用 updateAndGet/getAndUpdate 等封装方法。

Java 中用 AtomicReference 实现对象的原子更新,核心是利用其 compareAndSet(CAS)操作,避免锁竞争,保证多线程下引用更新的线程安全。
理解 AtomicReference 的作用
AtomicReference 是一个线程安全的引用容器,它包装任意类型的对象引用,并提供原子性的读、写、比较并交换等操作。它不保证对象内部状态的线程安全,只保证“引用本身”的变更是原子的。
适合场景:需要频繁更新某个共享对象引用(如配置、状态、链表节点、无锁栈/队列中的头结点),且更新逻辑可基于当前值计算新值。
基本用法:compareAndSet 更新引用
最常用的方式是 compareAndSet(expected, updated) —— 仅当当前引用等于预期值时,才更新为新值,返回是否成功。
立即学习“Java免费学习笔记(深入)”;
- 它是一个乐观策略:先假设没冲突,尝试更新;失败则重试或处理逻辑
- 必须配合循环(通常用
do-while或for(;;))实现“自旋重试” - 注意:
expected和当前值使用==比较(不是.equals()),所以要小心对象复用问题
典型示例:线程安全的计数器包装类
虽然 AtomicInteger 更合适,但用 AtomicReference 可演示自定义对象的原子更新逻辑:
public class SafeCounter {
private final AtomicReference<Integer> value = new AtomicReference<>(0);
public void increment() {
Integer current;
Integer next;
do {
current = value.get();
next = current + 1;
} while (!value.compareAndSet(current, next));
}
public int get() {
return value.get();
}
}
这里每次读取当前值 → 计算新值 → 尝试 CAS 更新;若期间被其他线程抢先修改,compareAndSet 返回 false,循环重试。
更新复杂对象:确保不可变性或合理设计
如果包装的是自定义对象(比如 User),要注意:
- 推荐将对象设计为不可变(immutable):字段
final,不提供 setter,所有修改返回新实例 - 更新时创建新对象,再用 CAS 替换引用,避免多个线程看到中间不一致状态
- 例如:
userRef.compareAndSet(oldUser, oldUser.withAge(oldUser.age + 1)) - 避免在原对象上修改字段后直接 set —— 这会破坏原子性语义,也违背
AtomicReference的设计初衷
进阶技巧:updateAndGet / getAndUpdate
Java 8+ 提供更简洁的 API,内部已封装 CAS 自旋逻辑:
-
updateAndGet(UnaryOperator<T>):先计算新值,再更新并返回新值 -
getAndUpdate(UnaryOperator<T>):先计算新值,再更新并返回旧值 - 例如:
counter.updateAndGet(x -> x + 1)等价于上面的手动循环
这些方法底层仍是 CAS,但代码更清晰、不易出错,推荐优先使用。


















