atomicreference 是 java 中用于线程安全更新对象引用的工具类,仅保证引用本身的原子性,不保障对象内部状态安全;核心操作包括 get、set 和 compareandset,适用于无锁场景如配置切换、单例初始化等。

AtomicReference 是 Java 并发包(java.util.concurrent.atomic)中用于**线程安全地更新对象引用**的工具类。它不保证对象内部状态的线程安全,只保证“指向哪个对象”这个引用本身的读写和 CAS 操作是原子的。
核心用途:安全替换引用,避免锁
当你需要在多线程环境下,让一个变量指向不同的对象(比如切换配置、更新缓存、实现无锁栈/队列),又不想用 synchronized 或显式锁时,AtomicReference 就派上用场了。它的底层基于 CPU 的 CAS(Compare-And-Swap)指令,性能通常优于锁。
- 适合场景:共享一个可变引用(如
Node、Config、State对象),多个线程可能同时尝试更新它 - 不适合场景:频繁修改对象内部字段 —— 那得靠对象自身加锁或使用
AtomicIntegerFieldUpdater等字段更新器
基本用法:get/set + compareAndSet
初始化后,常用操作有三个:
-
get():获取当前引用值(线程安全的 volatile 读) -
set(newValue):设置新引用(线程安全的 volatile 写) -
compareAndSet(expected, updated):仅当当前值等于expected时,才设为updated;返回true表示成功,false表示失败(被其他线程抢先改了)—— 这是实现无锁逻辑的关键
例如,实现一个线程安全的“懒汉式”单例切换:
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
Service newSvc = new ServiceImpl();
// 只有当前没服务时才设置
if (currentService.compareAndSet(null, newSvc)) {
System.out.println("已初始化服务");
} else {
System.out.println("服务已被其他线程初始化");
}
进阶技巧:updateAndGet / getAndUpdate
Java 8+ 提供了更简洁的原子更新方式,避免手动循环重试:
-
updateAndGet(UnaryOperator<t> updateFunction)</t>:用函数计算新值,并原子性地更新、返回新值 -
getAndUpdate(UnaryOperator<t> updateFunction)</t>:用函数计算新值,原子性地更新、返回旧值
比如对一个包装了计数器的对象做原子递增:
AtomicReferencecounterRef.updateAndGet(c -> new Counter(c.value + 1)); // 创建新对象并替换引用
注意:这里每次都要创建新对象,因为对象不可变才安全;如果对象可变,就违背了原子引用的设计初衷。
注意事项:引用不变 ≠ 对象不变
AtomicReference 只保障“引用地址”的原子性,不约束其指向对象的内部状态。如果多个线程通过该引用拿到同一个对象并修改其字段,依然需要同步机制。
- 推荐配合不可变对象(Immutable Object)使用,比如
String、自定义的final字段类 - 若必须用可变对象,确保对象内部线程安全(如字段用
AtomicInteger、加锁等),或约定只读访问 - 慎用
lazySet():比set()更轻量,但不保证后续读操作立即看到,适合发布场景(如通知结束)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










