本文目录导读:

是的,Java 计数器 API(特别是 java.util.concurrent.atomic 包下的类)提供的是原子操作。
这些类通过硬件级别的原子指令(如 CAS,Compare-And-Swap 比较并交换)和 volatile 变量来实现线程安全的原子性,而无需使用重量级的 synchronized 锁。
核心原子计数器类
AtomicInteger:最常用的计数器。AtomicLong:用于长整型计数器(当计数可能超过 20 亿时)。AtomicBoolean:用于布尔状态标记。LongAdder/LongAccumulator:在高并发写入场景下,性能优于AtomicLong(通过内部分段减少竞争)。
关键原子方法示例
这些方法保证在多线程并发调用时,结果始终是正确的。
AtomicInteger counter = new AtomicInteger(0); // 1. 原子递增:相当于 i++,但线程安全 counter.incrementAndGet(); // 返回新值 (1) // 2. 原子递减 counter.decrementAndGet(); // 返回新值 (0) // 3. 获取当前值(原子读) int current = counter.get(); // 返回 0 // 4. 原子更新:预期值是 0,如果当前是 0,则更新为 10 boolean success = counter.compareAndSet(0, 10); // 成功,变为 10 // 5. 原子加法 int prev = counter.getAndAdd(5); // 返回旧值 10,新值变为 15
为什么说它是原子的?
-
底层原理:
- 普通变量(如
int i++)在底层是“读-改-写”三步操作,线程不安全。 AtomicInteger的incrementAndGet()内部调用Unsafe.compareAndSwapInt(),这是一个硬件级别的原子指令。- 它会在循环中尝试:如果当前值等于我读到的期望值,就更新,否则自旋重试,整个过程不会被中断。
- 普通变量(如
-
内存可见性:
AtomicInteger内部使用volatile int value存储数据。volatile保证了所有线程能立刻看到其他线程对计数值的修改。
对比:不使用原子的后果
// 反面例子:多线程下不安全
private int count = 0;
public void unsafeIncrement() {
count++; // 非原子操作,结果可能小于预期
}
// 正确方式:使用原子类
private AtomicInteger safeCount = new AtomicInteger(0);
public void safeIncrement() {
safeCount.incrementAndGet(); // 原子操作,结果绝对正确
}
性能建议
- 低/中并发:
AtomicInteger/AtomicLong足够。 - 超高并发(大量写入):使用
LongAdder,它会将计数分散到多个Cell中,最后需要时才汇总,减少 CAS 冲突。LongAdder counter = new LongAdder(); counter.increment(); // 高并发下性能更好 long total = counter.sum(); // 获取最终结果
| 特性 | 原子计数器 API | 普通 int + synchronized |
|---|---|---|
| 线程安全 | 是 | 是(但更重) |
| 原子性 | 硬件级保证 | 锁保证 |
| 性能 | 高(无锁/自旋) | 中(有锁,可能阻塞) |
| 使用复杂度 | 低 | 中(需小心锁范围) |
Java 的 AtomicInteger、AtomicLong 等计数器 API 是完全原子且线程安全的,是并发编程中推荐的首选计数器实现方案。