AtomicReference适用于单次原子赋值、无条件替换、配合compareAndSet实现乐观锁及构建非阻塞数据结构;其核心是compareAndSet,依赖==判断引用相等,不保证复合操作原子性。

AtomicReference 能让你安全地更新一个对象引用,前提是不依赖中间状态做复合操作;一旦涉及“读-改-写”逻辑(比如先取值再决定新值),就得配合 compareAndSet 手动重试,否则仍可能出错。
AtomicReference 适合什么场景
它解决的是“对某个引用变量的赋值操作本身要原子”这个问题,不是万能锁替代品。典型适用情况包括:
- 单次设置新对象,比如初始化一个缓存容器:
cacheRef.set(new ConcurrentHashMap()) - 无条件替换引用,如切换配置对象:
configRef.set(newConfig) - 配合
compareAndSet实现乐观锁式更新(需自行循环) - 作为更复杂原子结构的构建块,比如非阻塞栈或队列中的节点指针
compareAndSet 是核心,不是可选补充
很多人以为 set 或 get 就够用了,其实真正体现原子性的操作是 compareAndSet。它要求你明确提供“期望旧值”和“目标新值”,失败时返回 false,必须自己处理重试逻辑。
AtomicReferencecounter = new AtomicReference<>(0); Integer current; Integer next; do { current = counter.get(); next = current + 1; } while (!counter.compareAndSet(current, next));
这段代码模拟了原子自增——compareAndSet 失败说明其他线程抢先改了值,循环重新读取再试。漏掉这个循环,就退化成普通非线程安全操作。
立即学习“Java免费学习笔记(深入)”;
注意引用相等性判断陷阱
compareAndSet 内部用的是 == 判断引用是否相同,不是 equals。这意味着:
- 如果包装的是不可变对象(如
String、Integer),小数值可能被缓存,==偶尔碰巧成立,但不可依赖 - 自定义类必须确保你传入的
expectedValue是同一个对象实例,否则一定失败 - 不要试图用
compareAndSet(oldObj, newObj)替代“基于内容”的更新,那是业务逻辑该处理的事
它不解决复合操作的线程安全
AtomicReference 保证单次引用更新原子,但无法让多步操作整体原子。例如下面这段代码仍是线程不安全的:
if (ref.get() == null) {
ref.set(new ExpensiveObject()); // 两次独立原子操作,中间可能被抢占
}
这叫“检查后执行”(check-then-act)竞态。正确做法是用 compareAndSet(null, new ExpensiveObject()) 一次完成,或者改用 computeIfAbsent 等更高层工具。很多人卡在这一步,误以为用了 AtomicReference 就万事大吉。










