atomicreference 通过 cas 实现无锁线程安全更新,解决普通引用无法保证“读-改-写”原子性的问题;其 compareandset 等方法提供乐观锁语义,配合 updateandget 等 api 简化无锁编程,但需注意 aba 问题及对象内容非线程安全。

AtomicReference 是 Java 并发包(java.util.concurrent.atomic)中提供的一个原子引用类,它通过底层的 CAS(Compare-And-Swap)指令实现对对象引用的**无锁、线程安全的更新**,避免了 synchronized 或显式锁带来的性能开销和死锁风险。
为什么不能直接用普通引用赋值?
普通对象引用的赋值(如 obj = newObj)虽然是原子操作(JVM 规范保证引用赋值的原子性),但**读-改-写**类逻辑(比如“如果当前是 A,就设为 B”)不是原子的。多个线程同时执行这类判断+赋值,会导致竞态条件(Race Condition)。例如:
if (ref == oldObj) { // 线程1读到 oldObj<br> ref = newObj; // 线程2可能已在中间改掉了 ref<br>}
AtomicReference 的核心方法:compareAndSet
它提供 compareAndSet(expected, desired) 方法——仅当当前引用值等于 expected 时,才将引用设为 desired,并返回是否成功。整个过程由 CPU 硬件指令保证原子性。
✅ 安全写法示例:
- 定义原子引用:
AtomicReference<user> userRef = new AtomicReference(new User("Alice"));</user> - 条件更新(类似乐观锁):
boolean updated = userRef.compareAndSet(oldUser, newUser); - 循环重试(CAS 失败时自旋):
User current;<br>do {<br> current = userRef.get();<br>} while (!userRef.compareAndSet(current, update(current)));
配合更新函数实现无锁修改(updateAndGet / getAndUpdate)
Java 8+ 提供了更简洁的 API,避免手动写循环:
-
userRef.updateAndGet(u -> new User(u.name + "_v2")):基于当前值计算新值并原子更新,返回新值 -
userRef.getAndUpdate(u -> u.withAge(u.age + 1)):返回旧值,同时更新 -
userRef.accumulateAndGet(initial, (u, v) -> merge(u, v), BinaryOperator):适用于带初始值的累积场景
这些方法内部已封装 CAS 自旋逻辑,语义清晰且线程安全。
注意事项与常见陷阱
-
ABA 问题存在但影响有限:若引用从 A→B→A,
compareAndSet(A, C)仍会成功。多数业务场景(如状态机切换、单次更新)不敏感;如需严格防止,可用AtomicStampedReference加版本戳 - 引用本身不可变 ≠ 对象内容线程安全:AtomicReference 保证的是“引用指向谁”安全,不保证你 set 进去的对象内部字段是线程安全的。若需修改对象内容,应确保该对象是不可变的,或其字段本身也用原子类型/同步保护
- 避免在 lambda 中做耗时操作:updateAndGet 内部是自旋,若计算耗时长,会浪费 CPU,此时应考虑锁或其他并发结构
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











