原子变量适用于简单“读-改-写”场景,如计数、开关切换;不适用于多变量联动或含i/o的复合操作;需防伪共享并正确使用cas循环重试。

Java 原子变量是解决高并发下共享变量线程安全问题的轻量级方案,不依赖锁,靠硬件 CAS 指令保障原子性,兼顾性能与正确性。它不是万能替代品,但对计数、状态切换、简单引用更新等场景特别高效。
什么时候该用原子变量而不是 synchronized?
核心判断依据是操作是否满足“读-改-写”且逻辑简单。比如库存扣减、请求计数、开关标志位翻转、序列号生成——这些只需单次原子更新,无需复杂临界区协调。
- 适合:整型累加(AtomicInteger.incrementAndGet())、布尔状态切换(AtomicBoolean.compareAndSet(false, true))、对象引用替换(AtomicReference.set(new Config()))
- 不适合:涉及多个变量联动更新(如“扣库存同时增销量”,需事务语义)、含 I/O 或耗时逻辑的复合操作、需要等待条件满足的场景(此时应选 Lock + Condition 或 CountDownLatch)
避开伪共享,让原子变量真正快起来
多个原子变量若在内存中紧挨着(例如定义为相邻字段),可能落在同一 CPU 缓存行(64 字节)内。当不同 CPU 核心频繁修改其中不同变量时,会反复使整个缓存行失效,形成伪共享(False Sharing),吞吐量骤降。
- 验证方式:用 JProfiler 或 async-profiler 查看缓存未命中率(L1/L2 cache miss)是否异常偏高
- 修复方法:对原子变量前后填充无用长字段(@sun.misc.Contended 注解在 JDK 8+ 可启用,需启动参数 -XX:-RestrictContended);或直接将高频更新的原子变量拆到独立对象中,靠 JVM 对象布局自然隔离
正确使用 compareAndSet 实现自定义逻辑
CAS 不是黑盒,它的“预期值-更新值”机制决定了必须配合循环重试才能保证逻辑完整。比如实现“仅当库存大于 0 才扣减”:
- 错误写法:if (stock.get() > 0) stock.decrementAndGet(); —— 判断和扣减之间存在竞态窗口
- 正确写法:循环读取当前值 → 验证条件 → 构造新值 → CAS 更新 → 失败则重试
- 示例:
int current; do { current = stock.get(); if (current
比 AtomicInteger 更灵活的进阶用法
不是所有场景都适合新建原子类实例。已有业务对象中想原子更新某个字段,可用字段更新器;高频读写数组元素,用原子数组更省内存。
- AtomicIntegerFieldUpdater:对已有类的 public volatile int 字段做原子更新,避免为每个实例包装 AtomicInteger
- AtomicIntegerArray:适用于分片计数(如按用户 ID 哈希到不同槽位统计请求量),比创建 N 个 AtomicInteger 节省对象头开销
- LongAdder / DoubleAdder:在极端高并发累加场景(如百万 QPS 请求计数),比 AtomicInteger 吞吐量高数倍——它内部采用分段累加+最终合并策略,显著降低 CAS 冲突概率
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











