AtomicInteger
和 volatile Integer
虽然都与线程安全有关,但本质完全不同。它们的主要区别体现在原子性保证和功能上:
🔍 核心区别对比表
特性 | volatile Integer |
AtomicInteger |
---|---|---|
原子性 | ❌ 不保证复合操作原子性 | ✅ 保证所有操作的原子性 |
自增操作安全性 | ❌ i++ 不安全 |
✅ incrementAndGet() 安全 |
CAS 操作 | ❌ 不支持 | ✅ 原生支持 compareAndSet() |
函数式更新 | ❌ 不支持 | ✅ 支持 updateAndGet() |
性能表现 | 简单读写快 | 复合操作远优于锁同步 |
内部原理 | 内存屏障 + 禁止重排序 | volatile + CAS 自旋 |
⚠️ volatile Integer 的问题演示
public class VolatileCounter {
private volatile Integer count = 0;
// 线程不安全的操作!
public void increment() {
count++; // 实际分为三步: 读 -> 改 -> 写
}
public int getCount() {
return count;
}
}
问题代码解释:
- 当线程A读取
count=0
- 线程B同时读取
count=0
- 线程A计算
0+1=1
写入 - 线程B计算
0+1=1
写入 - 结果:实际执行了两次自增,值却只变为1
✅ AtomicInteger 解决方案
import java.util.concurrent.atomic.AtomicInteger;
public class SafeCounter {
private final AtomicInteger count = new AtomicInteger(0);
// 线程安全操作
public void safeIncrement() {
count.incrementAndGet(); // 原子操作
}
public int getCount() {
return count.get();
}
}
关键原理:
// AtomicInteger 内部实现原理
public final int incrementAndGet() {
return U.getAndAddInt(this, VALUE, 1) + 1;
}
// 实际执行(Unsafe类):
public final int getAndAddInt(Object o, long offset, int delta) {
int v;
do {
v = getIntVolatile(o, offset); // 1. 读取volatile值
} while (!weakCompareAndSetInt(v, v + delta)); // 2. CAS自旋
return v;
}
📌 本质区别总结
volatile 的作用
- 只保证可见性和有序性
- 写操作立即刷新到主存
- 读操作总是获取最新值
AtomicInteger 的优势
- 通过 volatile 变量 + CAS 自旋实现复合操作原子性
- 内置支持数学运算、比较交换等功能
- 封装了线程安全的无锁算法
性能对比场景
// 测试代码片段 for(int i=0; i<1000000; i++) { // volatile版:1000ms+ // AtomicInteger版:200ms }
🔄 关系示意图
volatile int value (基本保障)
│
▼
+-----------------+
| AtomicInteger |→ CAS保证复合操作原子性
| (封装增强) |→ 提供原子操作方法族
+-----------------+
可见
AtomicInteger
内部使用 volatile 保证可见性(通过private volatile int value
字段),但增加了 CAS 机制来实现更复杂的原子操作,这是单纯 volatile 做不到的。
💡 使用建议
- 需要单一基本类型的原子操作 → 用
AtomicInteger/Long/Boolean
- 需要简单可见性保证 → 用
volatile
- 需要对象引用的原子更新 → 用
AtomicReference
- JDK8+高并发计数场景 → 用
LongAdder