Atomic 原子类详解
Atomic 原子类基于 CAS 实现无锁并发,性能优于 synchronized,是高并发场景的首选。
一、为什么需要原子类
1.1 synchronized 问题
// synchronized 实现计数
private int count = 0;
public synchronized void increment() {
count++;
}
// 问题:
// 1. 重量级锁,性能开销大
// 2. 阻塞线程,上下文切换成本高
1.2 CAS 方案
// CAS 实现计数
private AtomicInteger count = new AtomicInteger(0);
public void increment() {
count.incrementAndGet(); // 无锁,性能高
}
// 优势:
// 1. 无锁,非阻塞
// 2. 硬件级 CAS 指令支持
// 3. 高并发下性能优异
二、CAS 原理
2.1 什么是 CAS
CAS = Compare And Swap
三个操作数:
- V:内存值
- A:预期值
- B:新值
流程:
1. 比较 V 和 A
2. 如果相等,V = B
3. 如果不等,重试
2.2 硬件支持
// x86 汇编指令
lock cmpxchg
// lock 前缀保证原子性
// 锁定总线或缓存行
2.3 ABA 问题
线程 1: 读取 A → 准备修改
线程 2: A → B → A
线程 1: 比较成功(还是 A),修改
问题:看似没变,实际已被修改过
解决方案:版本号
AtomicStampedReference<Integer> ref =
new AtomicStampedReference<>(0, 0);
// 增加版本号,检测 ABA
ref.compareAndSet(
expectedValue,
newValue,
expectedStamp, // 预期版本
newStamp // 新版本
);
三、基本类型原子类
3.1 AtomicInteger
AtomicInteger atomic = new AtomicInteger(0);
// 自增操作
atomic.incrementAndGet(); // ++i,返回新值
atomic.getAndIncrement(); // i++,返回旧值
// 自减操作
atomic.decrementAndGet(); // --i
atomic.getAndDecrement(); // i--
// 加减操作
atomic.addAndGet(5); // this += 5
atomic.getAndAdd(5); // this += 5
// 设置操作
atomic.set(10); // this = 10
atomic.compareAndSet(10, 20); // CAS: if this==10 then this=20
// 获取值
int value = atomic.get();
3.2 AtomicLong
AtomicLong atomic = new AtomicLong(0);
// 操作同 AtomicInteger
atomic.incrementAndGet();
3.3 AtomicBoolean
AtomicBoolean atomic = new AtomicBoolean(false);
// 设置并获取
boolean oldValue = atomic.getAndSet(true);
// CAS
boolean success = atomic.compareAndSet(false, true);
四、数组类型原子类
4.1 AtomicIntegerArray
int[] arr = {1, 2, 3};
AtomicIntegerArray atomic = new AtomicIntegerArray(arr);
// 获取/设置
int value = atomic.get(0); // 1
atomic.set(0, 10); // arr[0] = 10
// CAS
atomic.compareAndSet(0, 10, 20); // if arr[0]==10 then arr[0]=20
// 自增
atomic.incrementAndGet(0); // ++arr[0]
4.2 AtomicReferenceArray
String[] arr = {"a", "b", "c"};
AtomicReferenceArray<String> atomic = new AtomicReferenceArray<>(arr);
// 获取/设置引用
String value = atomic.get(0);
atomic.set(0, "x");
五、引用类型原子类
5.1 AtomicReference
class User {
String name;
int age;
}
AtomicReference<User> ref = new AtomicReference<>();
// 设置
ref.set(new User("Alice", 20));
// CAS
User expected = new User("Alice", 20);
User updated = new User("Alice", 21);
boolean success = ref.compareAndSet(expected, updated);
// 获取
User user = ref.get();
5.2 AtomicStampedReference
// 解决 ABA 问题
AtomicStampedReference<Integer> ref =
new AtomicStampedReference<>(0, 0);
// CAS 带版本号
ref.compareAndSet(
0, // 预期值
1, // 新值
0, // 预期版本
1 // 新版本
);
// 获取版本号
int stamp = ref.getStamp();
5.3 AtomicMarkableReference
// 标记位代替版本号
AtomicMarkableReference<Integer> ref =
new AtomicMarkableReference<>(0, false);
// 设置标记
ref.attemptMark(0, true);
// 获取标记
boolean marked = ref.isMarked();
六、LongAdder(高性能计数器)
6.1 为什么需要 LongAdder
// AtomicInteger 高并发问题
AtomicInteger count = new AtomicInteger(0);
// 大量线程竞争同一个变量
// CAS 失败率高,频繁自旋
// LongAdder 方案
LongAdder count = new LongAdder();
count.increment(); // 性能提升 3-5 倍
6.2 实现原理
LongAdder = base + Cell[] 数组
线程通过哈希选择 Cell
↓
减少竞争,分散更新
↓
sum() = base + ΣCell[i].value
graph TB
A[线程 1] -->|hash| C1[Cell 0]
A2[线程 2] -->|hash| C2[Cell 1]
A3[线程 3] -->|hash| C3[Cell 2]
C1 --> S[sum]
C2 --> S
C3 --> S
6.3 使用示例
LongAdder adder = new LongAdder();
// 自增
adder.increment();
adder.add(5);
// 获取值
long sum = adder.sum();
long sumThenReset = adder.sumThenReset();
// 适用场景
// ✅ 高并发计数
// ✅ 统计汇总
// ❌ 需要精确 CAS 操作
6.4 性能对比
// 100 线程,100 万次自增
AtomicInteger: ~5000ms
LongAdder: ~1000ms
// 性能提升 5 倍!
七、实战场景
7.1 计数器
public class Counter {
private final LongAdder count = new LongAdder();
public void increment() {
count.increment();
}
public long getCount() {
return count.sum();
}
}
7.2 限流器
public class RateLimiter {
private final AtomicLong lastTime = new AtomicLong(0);
private final int limit;
public boolean tryAcquire() {
long now = System.currentTimeMillis();
long last = lastTime.get();
if (now - last > 1000) {
if (lastTime.compareAndSet(last, now)) {
return true;
}
}
return false;
}
}
7.3 状态机
public class StateMachine {
private final AtomicReference<State> state =
new AtomicReference<>(State.INIT);
public boolean transition(State expected, State updated) {
return state.compareAndSet(expected, updated);
}
public State getState() {
return state.get();
}
}
enum State {
INIT, RUNNING, COMPLETED, FAILED
}
7.4 缓存更新
public class Cache {
private final AtomicReference<Map<String, Object>> cache =
new AtomicReference<>(new HashMap<>());
public void refresh(Map<String, Object> newCache) {
cache.set(newCache); // 原子替换
}
public Object get(String key) {
return cache.get().get(key);
}
}
八、最佳实践
8.1 选择建议
| 场景 | 推荐 | 说明 |
|---|---|---|
| 单变量计数 | LongAdder | 高并发性能优 |
| CAS 操作 | AtomicInteger | 精确控制 |
| 引用对象 | AtomicReference | 原子更新引用 |
| ABA 问题 | AtomicStampedReference | 带版本号 |
| 数组操作 | AtomicIntegerArray | 数组元素原子操作 |
8.2 注意事项
// ❌ 错误:复合操作不原子
AtomicInteger count = new AtomicInteger(0);
count.set(count.get() + 1); // 非原子!
// ✅ 正确
count.incrementAndGet();
// ❌ 错误:多个变量不保证原子
AtomicInteger x = new AtomicInteger(0);
AtomicInteger y = new AtomicInteger(0);
// x 和 y 的更新不原子
// ✅ 正确:使用锁
synchronized (lock) {
x.incrementAndGet();
y.incrementAndGet();
}
8.3 性能优化
// 高并发场景优先 LongAdder
LongAdder counter = new LongAdder();
// 需要 CAS 操作用 AtomicInteger
AtomicInteger status = new AtomicInteger(0);
// 避免频繁创建对象
// ❌ 每次创建
new AtomicInteger(0)
// ✅ 复用实例
private static final AtomicInteger COUNTER = new AtomicInteger(0);
九、总结
Atomic 原子类核心要点:
| 类型 | 类名 | 适用场景 |
|---|---|---|
| 基本类型 | AtomicInteger/Long/Boolean | 单变量原子操作 |
| 数组类型 | AtomicIntegerArray/ReferenceArray | 数组元素原子操作 |
| 引用类型 | AtomicReference | 对象引用原子更新 |
| ABA 问题 | AtomicStampedReference | 带版本号 CAS |
| 高性能 | LongAdder | 高并发计数 |
原子类基于 CAS 实现无锁并发,高并发场景性能优于 synchronized。