AtomicIntegerFieldUpdater 是用于无锁原子更新对象中 public volatile int 字段的工具,需通过 newUpdater() 创建,要求字段严格满足可见性、可访问性及声明类一致性;适用于减少内存开销的高频实例场景,但牺牲封装性且需手动保障业务逻辑原子性。

AtomicIntegerFieldUpdater 是用来对对象里某个 volatile int 字段做无锁原子更新的工具,不是给任意字段用的,更不是替代 AtomicInteger 的通用方案。
为什么不能直接 new AtomicIntegerFieldUpdater?
它必须通过 newUpdater() 静态工厂方法创建,且要求字段满足严格条件:
- 字段必须是
public volatile int(不能是private或protected,也不能是final) - 字段所在类必须和 updater 创建时传入的泛型类型完全一致(子类字段不行)
- 字段名必须是字符串字面量,运行时无法动态拼接(比如不能写
"count" + suffix) - 字段不能在父类中定义后被子类继承使用(updater 绑定的是声明该字段的具体类)
常见错误现象:RuntimeException: java.lang.IllegalArgumentException: Must be public and volatile,哪怕你加了 volatile 但用了 private 修饰符,也会报这个错。
和 AtomicInteger 相比,什么时候该选 AtomicIntegerFieldUpdater?
核心权衡点是「内存开销」和「对象生命周期」:
立即学习“Java免费学习笔记(深入)”;
- 当你已有大量实例,每个都配一个
AtomicInteger字段,会显著增加堆内存占用(每个AtomicInteger是独立对象,含对象头 + int + padding) - 而
AtomicIntegerFieldUpdater是单例共享的,只更新原始字段,不新增对象引用 - 典型场景:高并发消息对象、事件对象、状态容器(如 Netty 的
AbstractReferenceCounted就用它更新引用计数) - 但代价是:字段必须是
public volatile,破坏封装性;且反射机制带来轻微性能开销(JVM 优化后差距很小)
示例:
public class Counter {
public volatile int value = 0;
}
AtomicIntegerFieldUpdater<Counter> updater = AtomicIntegerFieldUpdater.newUpdater(Counter.class, "value");
注意:这里 "value" 必须和字段名完全一致,大小写敏感,且不能是 getter 方法名。
容易被忽略的线程安全陷阱
很多人以为用了 updater 就“万事大吉”,其实关键逻辑仍需自己保证原子性边界:
-
updater.compareAndSet(obj, expect, update)只保证单次 CAS 成功与否,不保证整个业务逻辑原子 —— 比如“读-改-写”三步仍需额外同步或重试 - 字段被其他代码直接赋值(绕过 updater)会破坏一致性,因为
volatile写语义虽保留,但非原子操作可能覆盖 CAS 中间态 - 在 lambda 或异步回调里捕获对象引用时,要确认该对象没被提前回收(尤其在堆外内存或池化场景下)
- Android 上低版本(API AtomicIntegerFieldUpdater 支持不完整,反射限制可能导致
RuntimeException
最常踩的坑是:把 updater 当作“自动同步器”,结果在多线程反复读写同一字段时,漏掉了 compareAndSet 失败后的重试逻辑,导致更新静默丢失。
它解决的是“字段级原子写”的窄问题,不是“业务逻辑原子性”的宽问题。字段得公开、得 volatile、得稳定存在,否则连初始化都过不去。


















