atomicreference仅保证引用替换原子性,不保障对象内部线程安全;适用不可变对象或整体替换场景,需避免复用可变实例、忽略aba问题及重试逻辑。

AtomicReference 可以对自定义业务对象做原子更新,但关键不是“能不能”,而是“怎么确保语义正确”——它只保证引用本身的读写是原子的,不自动保证对象内部状态的线程安全。
理解 AtomicReference 的原子性边界
AtomicReference 保障的是“把一个引用替换成另一个引用”这个操作不可中断(compareAndSet、getAndSet 等),但它不递归保护对象内部字段。比如你有一个 Account 类,含 balance 字段,用 AtomicReference
所以适用场景通常是:
- 业务对象本身是不可变的(immutable)(推荐)
- 或者你只通过“整体替换”来改变状态,不复用/修改旧实例
推荐做法:用不可变对象 + CAS 循环
定义业务对象时让所有字段 final,并提供带全参数的构造器。每次状态变更都创建新实例,再用 compareAndSet 尝试原子替换:
public final class OrderState {
public final String orderId;
public final OrderStatus status;
public final BigDecimal amount;
<pre class="brush:java;toolbar:false;">public OrderState(String orderId, OrderStatus status, BigDecimal amount) {
this.orderId = orderId;
this.status = status;
this.amount = amount;
}
// 返回新状态实例,不修改自身
public OrderState withStatus(OrderStatus newStatus) {
return new OrderState(orderId, newStatus, amount);
}}
更新逻辑示例(如将订单从 CREATED → PROCESSING):
AtomicReference<orderstate> stateRef = new AtomicReference(
new OrderState("ORD-001", OrderStatus.CREATED, new BigDecimal("99.99"))
);
<p>boolean success = false;
while (!success) {
OrderState current = stateRef.get();
if (current.status == OrderStatus.CREATED) {
OrderState next = current.withStatus(OrderStatus.PROCESSING);
success = stateRef.compareAndSet(current, next);
} else {
break; // 状态已变,不再尝试
}
}</p></orderstate>避免常见陷阱
- 不要复用可变对象:如果 OrderState 不是 final 字段或提供了 setter,多个线程拿到同一实例后并发修改,CAS 成功也无意义
- 注意 ABA 问题:若对象被替换两次又变回“相同值”(如 OrderState 实例内容一样但不是同一个对象),CAS 仍会成功。一般业务对象含唯一 ID 或版本号时影响不大;若敏感,可用 AtomicStampedReference 或加版本字段
- 别忽略失败重试逻辑:compareAndSet 可能失败,必须循环重试或降级处理,不能只调一次就假设成功
- 初始化要显式设置:用 new AtomicReference(initialValue),避免 get() 返回 null 导致 NPE
什么时候不适合用 AtomicReference?
当业务对象字段多、更新频繁且每次只改其中一两个字段时,为每次更新都新建对象+CAS,可能带来较多临时对象和重试开销。此时更合适的是:
- 对关键字段单独用 AtomicInteger / AtomicLong(如只原子更新余额)
- 或使用 ReadWriteLock / synchronized 控制对象整体访问
- 或选用更高级的并发结构(如 StampedLock、CopyOnWriteArrayList 等,视场景而定)










