atomicreference仅保证引用操作原子性,不保证内部状态原子性;需配合不可变对象与cas循环实现安全更新,避免直接修改可变对象。

AtomicReference 本身不能直接保证“复杂对象内部状态”的原子性,它只保证对引用本身的读取、赋值、CAS 等操作是原子的。要实现复杂对象引用的原子更新,关键在于让被引用的对象是不可变的(Immutable),或确保每次更新都生成一个全新对象,再用 CAS 替换引用。
用不可变对象配合 AtomicReference 实现安全更新
如果复杂对象的所有字段都是 final,且没有提供修改内部状态的方法(即真正不可变),那么只要用 AtomicReference 持有它的引用,所有“读-改-写”逻辑就能基于新实例 + CAS 安全完成。
- 定义一个包含多个字段的不可变类,所有字段用 final 修饰,构造函数初始化,不暴露 setter 或可变集合
- 每次需要“更新”时,不是修改原对象,而是创建一个新对象(例如 copy-on-write:复制旧值,修改目标字段,构造新实例)
- 调用 compareAndSet(oldRef, newRef) 尝试原子替换引用;失败则重试(通常放在循环里)
典型场景:线程安全地维护带版本号的状态
比如一个计数器 + 时间戳组合,希望原子更新二者。可以封装成不可变类:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
final long count;
final long version;
VersionedCount(long count, long version) {
this.count = count;
this.version = version;
}
}
然后用 AtomicReference
- 获取当前值:current = ref.get()
- 构造新值:next = new VersionedCount(current.count + 1, current.version + 1)
- 尝试更新:ref.compareAndSet(current, next),失败则重试
避免常见陷阱:不要在原对象上做修改
如果复杂对象是可变的(比如普通 JavaBean),即使包装在 AtomicReference 中,多个线程仍可能同时修改其内部字段,导致数据不一致。
- ❌ 错误做法:拿到引用后直接调用 obj.setValue(…) —— 这不涉及 AtomicReference,完全不原子
- ❌ 避免共享可变对象:不要让多个线程持有同一个可变对象的引用并并发修改
- ✅ 正确思路:把“修改逻辑”收敛到创建新对象这一步,确保 AtomicReference 只参与引用层面的 CAS
结合乐观锁思想,用循环+CAS 实现无锁更新
AtomicReference 的核心价值在于支持无锁算法。实际编码中常用 do-while 循环模拟 CAS 自旋:
- 先 get() 获取当前引用
- 基于当前值计算出期望的新值(必须是新对象实例)
- 调用 compareAndSet,成功则退出;失败说明期间有其他线程已更新,重新读取再试
- 注意控制重试次数,防止长时间自旋(必要时可加 Thread.yield() 或短暂 sleep)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










