
AtomicInteger incrementAndGet 为什么比 synchronized 快
因为不加锁,靠 CPU 的 CAS(Compare-And-Swap)指令原子更新值,避免线程阻塞和上下文切换开销。
但要注意:CAS 在高竞争下会反复重试,反而比锁更耗 CPU;不是所有场景都更快。
- 适合读多写少、冲突概率低的计数器场景(如请求统计、序列号生成)
- 不适合需要复合操作的逻辑(比如“先读再判断再写”,
AtomicInteger本身不保证这个整体原子性) -
incrementAndGet()返回新值,getAndIncrement()返回旧值,别用反了
AtomicReference 的 compareAndSet 容易误用 null
compareAndSet 是 AtomicReference 的核心方法,但传 null 当预期值时,语义和普通引用比较一致——即只在当前值为 null 时才成功。
常见错误是以为 null 表示“任意值”或“忽略检查”,其实不是。
- 如果想实现“无条件更新”,得用
set(),而不是compareAndSet(old, new)配null - 当对象本身可能为
null,又需要 CAS 更新,建议封装成非空 wrapper 类,避免歧义 - 注意 JVM 对
null的内存可见性:AtomicReference的get()总能读到最新写入,包括null
AtomicStampedReference 解决 ABA 问题但代价明显
当一个值从 A → B → A 变化后,compareAndSet 会误判为“没变过”,导致逻辑出错。这就是 ABA 问题。AtomicStampedReference 通过给引用带上版本戳来规避。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
但它不是银弹:
- 每次操作要同时处理引用和整型 stamp,API 更啰嗦,容易写错顺序(比如把 stamp 和 reference 传反)
- stamp 溢出后行为未定义,实际使用中需控制 stamp 增长节奏(比如用
AtomicInteger管理,但别让它狂增) - 多数业务场景根本不存在真实 ABA,盲目上
AtomicStampedReference只是增加复杂度和内存开销
AtomicIntegerFieldUpdater 的反射限制很硬
它允许对普通对象字段做原子更新,但要求字段必须是 volatile int、public(或同包)、且不能是 final —— 这些检查在类加载时就做,失败直接抛 RuntimeException。
最常踩的坑是字段访问权限不对,或者用了 Lombok 的 @Getter/@Setter 却忘了加 volatile。
- 字段声明必须显式带
volatile,哪怕你只用 updater 更新,JVM 也不认“隐式 volatile” - 不能用于子类字段(updater 绑定的是声明该字段的类),否则运行时报
IllegalArgumentException - 泛型类里的字段无法安全 updater(类型擦除导致运行时字段签名不匹配)
真正难的不是记住这些类怎么用,而是判断某个变量是否真的需要原子性、以及该选哪个原子类——很多时候一个 synchronized 方法或 ReentrantLock 更直白可靠。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










