atomicreference仅保证引用原子性,需结合不可变对象与cas循环实现复杂状态的原子更新:每次更新创建新实例并用compareandset替换引用,推荐使用updateandget简化逻辑。

AtomicReference 本身不保证对象内部状态的原子性,只保证“引用”本身的读写是原子的。要安全更新自定义复杂对象,关键不是让对象变“原子”,而是通过“无锁 + CAS + 不可变设计”来实现逻辑上的原子更新。
核心思路:用不可变对象 + CAS 循环重试
不能直接修改对象字段(那会破坏线程安全),而是每次更新都创建新对象,再用 compareAndSet 原子替换整个引用:
- 把自定义类设计为不可变(immutable):所有字段
final,构造后不修改 - 每次“更新”实际是基于旧值计算出一个新实例
- 用
AtomicReference.compareAndSet(expected, updated)尝试替换;失败说明期间被其他线程改过,就重试
典型例子:计数器 + 时间戳封装
比如想原子地同时更新计数值和最后修改时间:
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
public final class CounterState {
public final int count;
public final long timestamp;
public CounterState(int count, long timestamp) {
this.count = count;
this.timestamp = timestamp;
}
// 返回新状态:count+1,时间更新为当前
public CounterState increment() {
return new CounterState(count + 1, System.nanoTime());
}
}
// 使用
AtomicReference<counterstate> state = new AtomicReference(
new CounterState(0, System.nanoTime())
);
// 原子递增
public void increment() {
CounterState current;
CounterState next;
do {
current = state.get();
next = current.increment();
} while (!state.compareAndSet(current, next));
}</counterstate>
避免常见陷阱
-
别在对象里暴露可变字段:如果
CounterState有个public List<string> logs</string>,外部改了它,就破坏了不可变契约 - 不要在 CAS 循环里做耗时操作:比如网络调用、IO,会显著增加冲突重试概率
-
注意 ABA 问题是否真影响业务:多数场景(如计数、状态机)不关心中间是否绕回,无需用
AtomicStampedReference - 大对象频繁创建?考虑对象池或结构拆分:但需权衡 GC 开销与锁竞争,通常小对象 JVM 优化很好
进阶:用 updateAndGet 简化代码
JDK 8+ 提供更简洁的 API,自动处理循环逻辑:
state.updateAndGet(current -> current.increment());
等价于上面的手动 do-while,语义更清晰,推荐优先使用。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










