直接使用java.util.concurrent.atomic包中的原子类可无锁保证跨线程更新原子性,其核心是通过cas指令实现“读—改—写”不可分割;需按场景选用atomicinteger/long、atomicboolean、atomicreference等,并正确使用incrementandget、compareandset等方法。

直接用 java.util.concurrent.atomic 包里的原子类,就能在不加锁的前提下确保跨线程更新的原子性。核心在于它们把“读—改—写”这三步压缩成一条不可分割的 CPU 指令(CAS),中间不会被其他线程打断。
选对原子类:按数据类型和使用场景匹配
不是所有变量都适合套用同一个原子类,得看你要操作的是什么:
-
整数计数器(比如请求量、任务完成数)→ 用
AtomicInteger或AtomicLong;高并发写多读少时,优先考虑LongAdder(性能更好) -
开关或状态标志(如服务是否启用、任务是否完成)→ 用
AtomicBoolean,它不支持加减,但compareAndSet很适合做状态跃迁 -
对象引用变更(如切换配置对象、更新缓存实例)→ 用
AtomicReference;若需防 ABA 问题(值被改回原样),选AtomicStampedReference -
数组中某一项更新(如分片统计、索引位计数)→ 用
AtomicIntegerArray,它只保证单个元素操作原子,不锁整个数组
关键操作要会用:别再写 count++
count++ 在字节码里是三步:读当前值 → 加1 → 写回去。多线程下极易丢失更新。原子类提供了真正安全的替代方法:
-
incrementAndGet():自增后返回新值,适合“先加再用”场景 -
getAndIncrement():返回旧值后再自增,适合“用完再加”逻辑 -
addAndGet(delta):支持任意增量,比多次incrementAndGet更简洁 -
compareAndSet(expected, newValue):带条件更新,常用于实现无锁状态机或初始化保护
实战注意点:避开常见坑
原子类虽好,但用错地方反而埋雷:
- 它只保障单个变量的操作原子性。如果业务逻辑涉及多个变量联动(比如余额减少+流水增加),原子类无法覆盖,得靠锁或事务
-
AtomicReference的set()和get()是 volatile 语义,能保证可见性,但updateAndGet这类复合操作才真正原子 - 字段更新器(如
AtomicIntegerFieldUpdater)要求目标字段必须是volatile,且不能是private(否则反射失败) - JDK 21 起所有原子类底层已统一基于
VarHandle,无需手动调用Unsafe,兼容性和安全性更有保障
一个真实计数器示例
下面代码模拟 5 个线程各执行 1000 次递增,最终结果稳定为 5000:
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class SafeCounter {
private static final AtomicInteger counter = new AtomicInteger(0);
public static void main(String[] args) throws InterruptedException {
ExecutorService pool = Executors.newFixedThreadPool(5);
for (int i = 0; i {
for (int j = 0; j











