Skip to content
清晨的一缕阳光
返回

Atomic 原子类详解

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。


分享这篇文章到:

上一篇文章
并发工具类实战
下一篇文章
Java 内存模型 (JMM) 详解