跳到主要内容

原子类

原子类是 JUC 提供的一组基于 CAS(Compare-And-Swap)实现的线程安全操作类。与使用锁相比,原子类采用无锁算法,在低竞争场景下性能更优。

CAS 原理

CAS(Compare-And-Swap)是一种乐观锁机制,它包含三个操作数:

  • V(Value):内存值
  • E(Expected):预期值
  • N(New):新值

CAS 操作的语义是:如果内存值 V 等于预期值 E,则将内存值更新为 N,否则不做任何操作。

CAS vs 锁

public class CounterComparison {
private int countWithLock = 0;
private AtomicInteger countWithCAS = new AtomicInteger(0);
private final Object lock = new Object();

public void incrementWithLock() {
synchronized (lock) {
countWithLock++;
}
}

public void incrementWithCAS() {
countWithCAS.incrementAndGet();
}
}

锁的缺点

  • 线程切换开销大
  • 可能导致死锁
  • 优先级反转问题

CAS 的优点

  • 无锁,不会阻塞线程
  • 不会死锁
  • 在低竞争场景下性能更好

CAS 的缺点

  • ABA 问题
  • 循环时间长开销大(高竞争时)
  • 只能保证一个共享变量的原子性

ABA 问题

ABA 问题是指一个值原来是 A,变成了 B,又变回了 A。CAS 检查时发现值仍然是 A,认为没有变化,实际上已经发生了变化。

import java.util.concurrent.atomic.AtomicStampedReference;

public class ABADemo {
public static void main(String[] args) {
AtomicStampedReference<Integer> ref = new AtomicStampedReference<>(100, 0);

new Thread(() -> {
int stamp = ref.getStamp();
System.out.println("线程1 读取值: " + ref.getReference() + ", 版本: " + stamp);

try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}

boolean success = ref.compareAndSet(100, 101, stamp, stamp + 1);
System.out.println("线程1 CAS 结果: " + success);
}).start();

new Thread(() -> {
int stamp = ref.getStamp();
ref.compareAndSet(100, 101, stamp, stamp + 1);
System.out.println("线程2 第一次修改: " + ref.getReference() + ", 版本: " + ref.getStamp());

ref.compareAndSet(101, 100, ref.getStamp(), ref.getStamp() + 1);
System.out.println("线程2 第二次修改: " + ref.getReference() + ", 版本: " + ref.getStamp());
}).start();
}
}

AtomicStampedReference 通过版本号解决了 ABA 问题。

基本类型原子类

AtomicInteger

import java.util.concurrent.atomic.AtomicInteger;

public class AtomicIntegerDemo {
public static void main(String[] args) throws InterruptedException {
AtomicInteger count = new AtomicInteger(0);

Thread[] threads = new Thread[10];
for (int i = 0; i < 10; i++) {
threads[i] = new Thread(() -> {
for (int j = 0; j < 1000; j++) {
count.incrementAndGet();
}
});
}

for (Thread t : threads) t.start();
for (Thread t : threads) t.join();

System.out.println("最终结果: " + count.get());
}
}

核心方法

方法说明
get()获取当前值
set(int)设置值
getAndSet(int)设置新值,返回旧值
compareAndSet(int, int)CAS 操作
getAndIncrement()自增,返回旧值
incrementAndGet()自增,返回新值
getAndDecrement()自减,返回旧值
decrementAndGet()自减,返回新值
getAndAdd(int)加指定值,返回旧值
addAndGet(int)加指定值,返回新值
updateAndGet(IntUnaryOperator)函数式更新
getAndUpdate(IntUnaryOperator)函数式更新,返回旧值

函数式更新

AtomicInteger count = new AtomicInteger(10);

int result = count.updateAndGet(x -> x * 2);
System.out.println(result); // 20

result = count.getAndUpdate(x -> x + 5);
System.out.println(result); // 20
System.out.println(count.get()); // 25

AtomicLong

与 AtomicInteger 类似,用于操作 long 类型:

import java.util.concurrent.atomic.AtomicLong;

public class AtomicLongDemo {
public static void main(String[] args) {
AtomicLong counter = new AtomicLong(0);

long result = counter.incrementAndGet();
System.out.println(result); // 1

result = counter.addAndGet(100);
System.out.println(result); // 101
}
}

AtomicBoolean

import java.util.concurrent.atomic.AtomicBoolean;

public class AtomicBooleanDemo {
private static AtomicBoolean initialized = new AtomicBoolean(false);

public static void init() {
if (initialized.compareAndSet(false, true)) {
System.out.println("执行初始化");
} else {
System.out.println("已经初始化过了");
}
}

public static void main(String[] args) {
init(); // 执行初始化
init(); // 已经初始化过了
init(); // 已经初始化过了
}
}

引用类型原子类

AtomicReference

import java.util.concurrent.atomic.AtomicReference;

public class AtomicReferenceDemo {
public static void main(String[] args) {
AtomicReference<User> userRef = new AtomicReference<>(new User("张三", 20));

User oldUser = userRef.get();
User newUser = new User("李四", 25);

boolean success = userRef.compareAndSet(oldUser, newUser);
System.out.println("更新结果: " + success);
System.out.println("当前用户: " + userRef.get());

userRef.updateAndGet(u -> new User(u.name(), u.age() + 1));
System.out.println("年龄+1后: " + userRef.get());
}
}

record User(String name, int age) {}

AtomicStampedReference

解决 ABA 问题的原子引用类,通过版本号标记:

import java.util.concurrent.atomic.AtomicStampedReference;

public class AtomicStampedReferenceDemo {
public static void main(String[] args) {
AtomicStampedReference<String> ref = new AtomicStampedReference<>("A", 0);

int[] stampHolder = new int[1];
String value = ref.get(stampHolder);
int stamp = stampHolder[0];

System.out.println("当前值: " + value + ", 版本: " + stamp);

boolean success = ref.compareAndSet("A", "B", stamp, stamp + 1);
System.out.println("第一次更新: " + success);

success = ref.compareAndSet("A", "B", stamp, stamp + 1);
System.out.println("第二次更新(版本不匹配): " + success);

value = ref.get(stampHolder);
System.out.println("当前值: " + value + ", 版本: " + stampHolder[0]);
}
}

AtomicMarkableReference

使用布尔标记而非版本号:

import java.util.concurrent.atomic.AtomicMarkableReference;

public class AtomicMarkableReferenceDemo {
public static void main(String[] args) {
AtomicMarkableReference<String> ref = new AtomicMarkableReference<>("数据", false);

boolean[] markHolder = new boolean[1];
String value = ref.get(markHolder);

System.out.println("值: " + value + ", 标记: " + markHolder[0]);

ref.compareAndSet("数据", "新数据", false, true);

value = ref.get(markHolder);
System.out.println("值: " + value + ", 标记: " + markHolder[0]);
}
}

数组类型原子类

AtomicIntegerArray

import java.util.concurrent.atomic.AtomicIntegerArray;

public class AtomicIntegerArrayDemo {
public static void main(String[] args) {
int[] array = {1, 2, 3, 4, 5};
AtomicIntegerArray atomicArray = new AtomicIntegerArray(array);

System.out.println("原始数组: " + array[0]); // 1

atomicArray.set(0, 10);
System.out.println("原子数组: " + atomicArray.get(0)); // 10
System.out.println("原始数组: " + array[0]); // 1(不受影响)

int oldValue = atomicArray.getAndIncrement(1);
System.out.println("索引1旧值: " + oldValue); // 2
System.out.println("索引1新值: " + atomicArray.get(1)); // 3

atomicArray.addAndGet(2, 100);
System.out.println("索引2加100后: " + atomicArray.get(2)); // 103

boolean success = atomicArray.compareAndSet(3, 4, 40);
System.out.println("CAS 结果: " + success); // true
System.out.println("索引3新值: " + atomicArray.get(3)); // 40
}
}

AtomicLongArray

与 AtomicIntegerArray 类似,用于 long 类型数组。

AtomicReferenceArray

import java.util.concurrent.atomic.AtomicReferenceArray;

public class AtomicReferenceArrayDemo {
public static void main(String[] args) {
AtomicReferenceArray<String> array = new AtomicReferenceArray<>(5);

array.set(0, "Hello");
array.set(1, "World");

String old = array.getAndSet(0, "Hi");
System.out.println("旧值: " + old); // Hello
System.out.println("新值: " + array.get(0)); // Hi
}
}

字段更新器

字段更新器可以对类的 volatile 字段进行原子更新,无需将整个类改为原子类。

AtomicIntegerFieldUpdater

import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;

public class AtomicFieldUpdaterDemo {
public static void main(String[] args) {
AtomicIntegerFieldUpdater<Person> ageUpdater =
AtomicIntegerFieldUpdater.newUpdater(Person.class, "age");

Person person = new Person("张三", 20);

ageUpdater.incrementAndGet(person);
System.out.println("年龄: " + person.age); // 21

ageUpdater.compareAndSet(person, 21, 25);
System.out.println("年龄: " + person.age); // 25
}
}

class Person {
volatile String name;
volatile int age;

Person(String name, int age) {
this.name = name;
this.age = age;
}
}

注意事项

  • 字段必须是 volatile
  • 字段必须是可见的(public 或同一包内)
  • 只能是实例字段,不能是静态字段

AtomicLongFieldUpdater 和 AtomicReferenceFieldUpdater

import java.util.concurrent.atomic.AtomicLongFieldUpdater;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

public class MultiFieldUpdaterDemo {
public static void main(String[] args) {
AtomicLongFieldUpdater<Account> balanceUpdater =
AtomicLongFieldUpdater.newUpdater(Account.class, "balance");

AtomicReferenceFieldUpdater<Account, String> statusUpdater =
AtomicReferenceFieldUpdater.newUpdater(Account.class, String.class, "status");

Account account = new Account(1000, "正常");

balanceUpdater.addAndGet(account, 500);
System.out.println("余额: " + account.balance); // 1500

statusUpdater.compareAndSet(account, "正常", "冻结");
System.out.println("状态: " + account.status); // 冻结
}
}

class Account {
volatile long balance;
volatile String status;

Account(long balance, String status) {
this.balance = balance;
this.status = status;
}
}

累加器

Java 8 引入了高性能累加器,在高并发场景下比 AtomicLong 性能更好。

LongAdder

import java.util.concurrent.atomic.LongAdder;

public class LongAdderDemo {
public static void main(String[] args) throws InterruptedException {
LongAdder adder = new LongAdder();

Thread[] threads = new Thread[100];
for (int i = 0; i < 100; i++) {
threads[i] = new Thread(() -> {
for (int j = 0; j < 10000; j++) {
adder.increment();
}
});
}

long start = System.currentTimeMillis();
for (Thread t : threads) t.start();
for (Thread t : threads) t.join();
long end = System.currentTimeMillis();

System.out.println("LongAdder 结果: " + adder.sum() + ", 耗时: " + (end - start) + "ms");
}
}

LongAdder vs AtomicLong

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.LongAdder;

public class PerformanceComparison {
public static void main(String[] args) throws InterruptedException {
int threadCount = 100;
int incrementPerThread = 100000;

AtomicInteger atomicInt = new AtomicInteger(0);
LongAdder adder = new LongAdder();

long start = System.currentTimeMillis();
Thread[] threads1 = new Thread[threadCount];
for (int i = 0; i < threadCount; i++) {
threads1[i] = new Thread(() -> {
for (int j = 0; j < incrementPerThread; j++) {
atomicInt.incrementAndGet();
}
});
}
for (Thread t : threads1) t.start();
for (Thread t : threads1) t.join();
long end = System.currentTimeMillis();
System.out.println("AtomicInteger: " + atomicInt.get() + ", 耗时: " + (end - start) + "ms");

start = System.currentTimeMillis();
Thread[] threads2 = new Thread[threadCount];
for (int i = 0; i < threadCount; i++) {
threads2[i] = new Thread(() -> {
for (int j = 0; j < incrementPerThread; j++) {
adder.increment();
}
});
}
for (Thread t : threads2) t.start();
for (Thread t : threads2) t.join();
end = System.currentTimeMillis();
System.out.println("LongAdder: " + adder.sum() + ", 耗时: " + (end - start) + "ms");
}
}

LongAdder 的优势

AtomicLong 在高并发时,多个线程同时竞争同一个变量,CAS 失败后不断重试,性能下降。

LongAdder 采用"分散热点"策略:维护一个 base 变量和一个 Cell 数组,不同线程更新不同的 Cell,最后将所有值累加。

LongAdder 结构:
base (基础值)
+
Cell[] cells (分散的累加单元)
├── Cell[0] → 线程1累加
├── Cell[1] → 线程2累加
└── Cell[n] → 线程n累加

最终结果 = base + Cell[0] + Cell[1] + ... + Cell[n]

LongAccumulator

LongAccumulator 比 LongAdder 更灵活,可以指定累加函数:

import java.util.concurrent.atomic.LongAccumulator;

public class LongAccumulatorDemo {
public static void main(String[] args) throws InterruptedException {
LongAccumulator maxAccumulator = new LongAccumulator(Long::max, Long.MIN_VALUE);
LongAccumulator sumAccumulator = new LongAccumulator(Long::sum, 0);

Thread[] threads = new Thread[10];
for (int i = 0; i < 10; i++) {
final int value = i * 100;
threads[i] = new Thread(() -> {
maxAccumulator.accumulate(value);
sumAccumulator.accumulate(value);
});
}

for (Thread t : threads) t.start();
for (Thread t : threads) t.join();

System.out.println("最大值: " + maxAccumulator.get()); // 900
System.out.println("总和: " + sumAccumulator.get()); // 4500
}
}

DoubleAdder 和 DoubleAccumulator

import java.util.concurrent.atomic.DoubleAdder;
import java.util.concurrent.atomic.DoubleAccumulator;

public class DoubleAdderDemo {
public static void main(String[] args) {
DoubleAdder adder = new DoubleAdder();
adder.add(1.5);
adder.add(2.5);
System.out.println("总和: " + adder.sum()); // 4.0

DoubleAccumulator maxAcc = new DoubleAccumulator(Double::max, Double.NEGATIVE_INFINITY);
maxAcc.accumulate(1.5);
maxAcc.accumulate(3.5);
maxAcc.accumulate(2.0);
System.out.println("最大值: " + maxAcc.get()); // 3.5
}
}

原子类选择指南

场景推荐类
简单计数器AtomicInteger / AtomicLong
高并发计数LongAdder / DoubleAdder
对象引用更新AtomicReference
解决 ABA 问题AtomicStampedReference
数组元素原子操作AtomicIntegerArray
类字段原子更新AtomicIntegerFieldUpdater
自定义累加逻辑LongAccumulator

小结

本章介绍了 JUC 提供的原子类:

  1. CAS 原理:乐观锁机制,无锁实现线程安全
  2. 基本类型原子类:AtomicInteger、AtomicLong、AtomicBoolean
  3. 引用类型原子类:AtomicReference、AtomicStampedReference
  4. 数组类型原子类:AtomicIntegerArray、AtomicLongArray
  5. 字段更新器:对 volatile 字段进行原子更新
  6. 累加器:LongAdder、LongAccumulator,高并发下性能更优

原子类是构建无锁数据结构的基础,在低竞争场景下比锁有更好的性能。但在高竞争场景下,LongAdder 等累加器是更好的选择。