1. 为什么需要原子类
多线程环境下,有个常见问题:
java
public class Counter {
private int count = 0;
public void increment() {
count++;
}
}
count++ 看似一行代码,实际分三步:
- 读取 count 的值
- 加 1
- 写回 count
多线程下可能发生:
线程A:读取 count=0
线程B:读取 count=0
线程A:count=1,写回
线程B:count=1,写回 // 线程A的结果被覆盖了
最终 count=1,但实际应该等于 2。
2. 解决办法
synchronized 加锁
java
public synchronized void increment() {
count++;
}
缺点:性能差,每次只能一个线程进入。
原子类
java
private AtomicInteger count = new AtomicInteger(0);
public void increment() {
count.incrementAndGet();
}
一行搞定,性能比 synchronized 高很多。
3. 常用原子类
AtomicInteger
java
AtomicInteger count = new AtomicInteger(0);
// 加1
count.incrementAndGet(); // ++i
count.getAndIncrement(); // i++
// 减1
count.decrementAndGet(); // --i
count.getAndDecrement(); // i--
// 加任意值
count.addAndGet(5);
// 获取值
int value = count.get();
// 设置值
count.set(100);
// CAS 操作
count.compareAndSet(100, 200); // 如果当前值是100,则设置为200
AtomicLong
和 AtomicInteger 用法一样,只是类型不同:
java
AtomicLong count = new AtomicLong(0);
count.incrementAndGet();
AtomicBoolean
java
AtomicBoolean flag = new AtomicBoolean(false);
// 设为 true
flag.set(true);
// CAS 操作
flag.compareAndSet(false, true);
AtomicReference
用来原子更新对象:
java
AtomicReference<User> userRef = new AtomicReference<>();
User user1 = new User("张三", 20);
User user2 = new User("李四", 25);
userRef.set(user1);
userRef.compareAndSet(user1, user2); // 如果当前是 user1,则改为 user2
4. 数组原子类
java
// 数组中某个元素原子操作
AtomicIntegerArray arr = new AtomicIntegerArray(new int[]{1, 2, 3});
arr.getAndAdd(0, 10); // 第一个元素加10
int value = arr.get(0); // 获取第一个元素
5. 累加器
jdk8 新增的,比 AtomicInteger 性能更高,专门用于累加场景:
java
LongAdder count = new LongAdder();
count.add(1);
count.increment();
long value = count.sum();
内部原理是把一个值拆成多个 Cell,减少竞争。适合高并发场景下的累加。
java
// AtomicInteger vs LongAdder
// 低并发:两者差不多
// 高并发:LongAdder 性能更好
6. 实战示例
计数器
java
public class PageViewCounter {
private AtomicInteger count = new AtomicInteger(0);
public void addView() {
count.incrementAndGet();
}
public int getViews() {
return count.get();
}
}
防止重复提交
java
public class SubmitService {
private AtomicBoolean submitting = new AtomicBoolean(false);
public void submit() {
// 如果已经在提交中,直接返回
if (!submitting.compareAndSet(false, true)) {
return;
}
try {
// 业务逻辑
doSubmit();
} finally {
submitting.set(false);
}
}
}
配置更新
java
public class ConfigHolder {
private AtomicReference<Config> configRef = new AtomicReference<>();
public void updateConfig(Config newConfig) {
configRef.updateAndGet(old -> newConfig);
}
public Config getConfig() {
return configRef.get();
}
}
7. 总结
| 类 | 用途 |
|---|---|
| AtomicInteger | 整数原子操作 |
| AtomicLong | 长整数原子操作 |
| AtomicBoolean | 布尔原子操作 |
| AtomicReference | 对象引用原子操作 |
| AtomicIntegerArray | 整数数组原子操作 |
| LongAdder | 高并发累加,比 AtomicLong 性能更好 |
什么时候用:
- 需要保证多线程安全地修改一个值时
- 简单计数、状态标记等场景
- 比 synchronized 性能更好