原子类
原子类是 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 提供的原子类:
- CAS 原理:乐观锁机制,无锁实现线程安全
- 基本类型原子类:AtomicInteger、AtomicLong、AtomicBoolean
- 引用类型原子类:AtomicReference、AtomicStampedReference
- 数组类型原子类:AtomicIntegerArray、AtomicLongArray
- 字段更新器:对 volatile 字段进行原子更新
- 累加器:LongAdder、LongAccumulator,高并发下性能更优
原子类是构建无锁数据结构的基础,在低竞争场景下比锁有更好的性能。但在高竞争场景下,LongAdder 等累加器是更好的选择。