Skip to content

原子类

java.util.concurrent.atomic 包提供了原子操作类,基于 CAS(Compare-And-Swap)实现无锁线程安全。

1. 什么是 CAS

CAS 是一种无锁算法,包含三个操作数:

  • V:内存值(要更新的变量)
  • E:预期值(期望的旧值)
  • N:新值

原理:当且仅当 V == E 时,才将 V 更新为 N,否则不做任何操作。

if (V == E) {
    V = N
    return true
} else {
    return false
}

2. 基本类型原子类

2.1 AtomicInteger

java
import java.util.concurrent.atomic.*;

AtomicInteger atomicInt = new AtomicInteger(0);

// 自增
atomicInt.incrementAndGet();  // ++i,返回新值
atomicInt.getAndIncrement();  // i++,返回旧值

// 自减
atomicInt.decrementAndGet();  // --i
atomicInt.getAndDecrement();  // i--

// 加法
atomicInt.addAndGet(10);      // i += 10,返回新值
atomicInt.getAndAdd(10);      // 返回旧值

// CAS 操作
boolean success = atomicInt.compareAndSet(10, 20);

// 获取并更新
atomicInt.getAndUpdate(x -> x * 2);

// 累加器
atomicInt.accumulateAndGet(5, Integer::sum);

2.2 其他基本类型

java
AtomicLong atomicLong = new AtomicLong(0);
AtomicBoolean atomicBoolean = new AtomicBoolean(false);

2.3 使用示例

java
// 线程安全的计数器
public class Counter {
    private AtomicInteger count = new AtomicInteger(0);
    
    public void increment() {
        count.incrementAndGet();
    }
    
    public int getCount() {
        return count.get();
    }
}

3. 引用类型原子类

3.1 AtomicReference

java
import java.util.concurrent.atomic.*;

AtomicReference<User> atomicRef = new AtomicReference<>(new User("Tom"));

// CAS 更新
User expected = atomicRef.get();
User newUser = new User("Jerry");
boolean success = atomicRef.compareAndSet(expected, newUser);

// getAndUpdate
User old = atomicRef.getAndUpdate(user -> new User(user.getName() + "_updated"));

3.2 ABA 问题

CAS 存在 ABA 问题:值从 A 变成 B,又变回 A,CAS 会认为没有变化。

线程1:读取值 A
线程2:A → B → A
线程1:CAS(A, C) 成功,但实际上值已经被修改过

3.3 AtomicStampedReference(解决 ABA)

通过版本号(stamp)解决 ABA 问题。

java
AtomicStampedReference<Integer> stampedRef = new AtomicStampedReference<>(1, 0);

// 获取值和版本号
int[] stampHolder = new int[1];
Integer value = stampedRef.get(stampHolder);
int stamp = stampHolder[0];

// CAS 时同时验证值和版本号
boolean success = stampedRef.compareAndSet(
    value,           // 期望值
    value + 1,       // 新值
    stamp,           // 期望版本号
    stamp + 1        // 新版本号
);

3.4 AtomicMarkableReference

使用布尔标记代替版本号。

java
AtomicMarkableReference<Integer> markableRef = new AtomicMarkableReference<>(1, false);

boolean[] markHolder = new boolean[1];
Integer value = markableRef.get(markHolder);
boolean marked = markHolder[0];

markableRef.compareAndSet(value, value + 1, marked, !marked);

4. 数组原子类

java
import java.util.concurrent.atomic.*;

// 整型数组
AtomicIntegerArray atomicArray = new AtomicIntegerArray(10);
atomicArray.getAndIncrement(0);  // 索引0的元素自增
atomicArray.addAndGet(1, 10);    // 索引1的元素加10

// 长整型数组
AtomicLongArray atomicLongArray = new AtomicLongArray(new long[]{1, 2, 3});

// 引用数组
AtomicReferenceArray<String> atomicRefArray = new AtomicReferenceArray<>(10);
atomicRefArray.set(0, "hello");

5. 字段更新器

可以原子更新对象的某个字段,无需继承原子类。

5.1 AtomicIntegerFieldUpdater

java
import java.util.concurrent.atomic.*;

public class User {
    private volatile int age;  // 必须是 volatile
    
    private static final AtomicIntegerFieldUpdater<User> AGE_UPDATER = 
        AtomicIntegerFieldUpdater.newUpdater(User.class, "age");
    
    public void incrementAge() {
        AGE_UPDATER.incrementAndGet(this);
    }
    
    public int getAge() {
        return age;
    }
}

5.2 限制条件

  • 字段必须是 volatile
  • 字段不能是 private(对于其他类)
  • 字段不能是 static

6. LongAdder 和 LongAccumulator

6.1 LongAdder

高性能计数器,适合高并发场景。

java
import java.util.concurrent.atomic.*;

LongAdder adder = new LongAdder();

// 累加
adder.increment();
adder.add(10);

// 获取值
long sum = adder.sum();

6.2 vs AtomicLong

特性AtomicLongLongAdder
实现单个变量 CAS分散热点
高并发性能较低较高
获取精确值⚠️ 仅适合最终汇总
适用场景低并发高并发统计

原理:LongAdder 在内部维护多个变量,减少竞争。

AtomicLong:
  所有线程竞争同一个变量 → 高冲突

LongAdder:
  ┌─────┐  ┌─────┐  ┌─────┐
  │Cell1│  │Cell2│  │Cell3│  → 分散到多个 Cell
  └─────┘  └─────┘  └─────┘
      │        │        │
      └────────┼────────┘

          sum() 汇总

6.3 LongAccumulator

更通用的累加器,支持自定义累加函数。

java
// 求最大值
LongAccumulator max = new LongAccumulator(Long::max, Long.MIN_VALUE);
max.accumulate(10);
max.accumulate(20);
max.accumulate(5);
System.out.println(max.get());  // 20

// 求乘积
LongAccumulator product = new LongAccumulator((x, y) -> x * y, 1);
product.accumulate(2);
product.accumulate(3);
product.accumulate(4);
System.out.println(product.get());  // 24

7. 原子类选择指南

场景推荐类
简单计数器AtomicInteger / AtomicLong
高并发计数器LongAdder
原子更新对象AtomicReference
解决 ABA 问题AtomicStampedReference
原子更新数组元素AtomicIntegerArray
原子更新对象字段AtomicIntegerFieldUpdater