Atomic原子类的实现原理
一、核心思想:无锁并发
Atomic原子类的核心是 CAS(Compare-And-Swap) 操作,它解决了传统synchronized锁的性能瓶颈问题:
java
// 传统加锁方式 vs CAS方式
public class LockVsCAS {
private int value;
// 方式一:synchronized(悲观锁)
public synchronized void increment() {
value++; // ① 获取锁 ② 执行 ③ 释放锁
}
// 方式二:CAS(乐观锁)
public void incrementAtomic() {
int oldValue, newValue;
do {
oldValue = value; // 读取当前值
newValue = oldValue + 1; // 计算新值
} while (!compareAndSwap(oldValue, newValue)); // 尝试更新
// 如果期间value被其他线程修改,则重试
}
}
二、核心机制:CAS(Compare-And-Swap)
1. CAS的底层原理
CAS是CPU级别的原子指令,在Java中通过Unsafe类的本地方法实现:
java
// 伪代码展示CAS原理
public class CASDemo {
// CAS核心操作(伪代码)
public boolean compareAndSwap(int expectedValue, int newValue) {
// 原子操作:比较并交换
if (currentValue == expectedValue) { // 检查值是否被其他线程修改
currentValue = newValue; // 未被修改,则更新
return true;
}
return false; // 被修改了,返回失败
}
// Java中的实际实现(通过Unsafe)
private static final Unsafe unsafe = Unsafe.getUnsafe();
private volatile int value;
private static final long valueOffset; // value字段的内存偏移量
static {
try {
// 获取value字段在对象内存布局中的偏移地址
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
public final boolean compareAndSet(int expect, int update) {
// 调用CPU的CAS指令
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
}
2. Unsafe 类的作用
java
// Unsafe提供了一系列硬件级别的原子操作
public class UnsafeCAS {
// 1. 对象字段操作
native long objectFieldOffset(Field f); // 获取字段偏移量
native int getIntVolatile(Object o, long offset); // 原子读
native boolean compareAndSwapInt( // CAS操作
Object o, long offset,
int expected, int x
);
// 2. 数组元素操作
native int arrayBaseOffset(Class arrayClass); // 数组基地址
native int arrayIndexScale(Class arrayClass); // 元素大小
native int getAndSetInt(Object o, long offset, int newValue);
// 3. 内存屏障(JDK 8+)
native void loadFence(); // 读屏障
native void storeFence(); // 写屏障
native void fullFence(); // 全屏障
}
三、Atomic原子类家族
1. 基础原子类
java
// AtomicInteger 源码分析
public class AtomicInteger extends Number implements java.io.Serializable {
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;
private volatile int value; // 关键:volatile保证可见性
// 核心方法:原子自增
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
// Unsafe中的实现
public final int getAndAddInt(Object o, long offset, int delta) {
int v;
do {
v = getIntVolatile(o, offset); // 原子读取当前值
} while (!compareAndSwapInt(o, offset, v, v + delta)); // CAS重试
return v;
}
// 其他常用方法
public final int incrementAndGet() {} // ++i
public final int getAndDecrement() {} // i--
public final boolean compareAndSet(int expect, int update) {} // CAS
public final int getAndUpdate(IntUnaryOperator updateFunction) {}
}
2. 数组原子类
java
// AtomicIntegerArray - 支持对数组元素的原子操作
public class AtomicIntegerArrayDemo {
private final AtomicIntegerArray array = new AtomicIntegerArray(10);
public void demo() {
// 原子更新数组元素
array.compareAndSet(0, 0, 100); // 如果array[0]==0,则设为100
// 底层实现:计算元素的内存地址
// 地址 = 数组基地址 + 索引 × 元素大小
long rawIndex = arrayOffset + (long) index * scale;
}
}
篇幅限制下面就只能给大家展示小册部分内容了。整理了一份核心面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafc
需要全套面试笔记及答案
【点击此处即可/免费获取】
3. 引用类型原子类
java
// AtomicReference - 原子更新对象引用
public class AtomicReferenceDemo {
static class User {
String name;
int age;
}
private AtomicReference<User> ref = new AtomicReference<>();
public void updateUser() {
User oldUser, newUser;
do {
oldUser = ref.get();
newUser = new User("Tom", oldUser.age + 1);
} while (!ref.compareAndSet(oldUser, newUser));
}
// AtomicStampedReference - 解决ABA问题
private AtomicStampedReference<Integer> stampedRef =
new AtomicStampedReference<>(100, 0);
public void solveABA() {
int[] stampHolder = new int[1];
int currentStamp, newStamp;
Integer currentRef, newRef;
do {
currentRef = stampedRef.get(stampHolder); // 同时获取引用和版本号
currentStamp = stampHolder[0];
newRef = currentRef + 10;
newStamp = currentStamp + 1; // 每次更新增加版本号
} while (!stampedRef.compareAndSet(
currentRef, newRef, currentStamp, newStamp
));
}
}
4. 字段更新器
java
// 原子更新对象的某个字段(无需修改类定义)
public class FieldUpdaterDemo {
static class Counter {
volatile int count; // 必须是volatile
}
public void demo() {
Counter counter = new Counter();
AtomicIntegerFieldUpdater<Counter> updater =
AtomicIntegerFieldUpdater.newUpdater(Counter.class, "count");
updater.incrementAndGet(counter); // 原子增加counter.count
// 应用场景:大量对象需要原子计数,避免为每个对象创建AtomicInteger
}
}
四、ABA问题及解决方案
1. ABA问题示例
java
public class ABAProblem {
private static AtomicInteger atomic = new AtomicInteger(100);
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
// 线程1:A->B
boolean success = atomic.compareAndSet(100, 101);
System.out.println("t1: 100->101 " + success);
success = atomic.compareAndSet(101, 100);
System.out.println("t1: 101->100 " + success);
});
Thread t2 = new Thread(() -> {
try {
Thread.sleep(100); // 确保t1先执行完ABA操作
} catch (InterruptedException e) {}
// 线程2:期望看到100,就改为200
boolean success = atomic.compareAndSet(100, 200);
System.out.println("t2: 100->200 " + success); // ✅ 成功!
// 问题:虽然成功了,但中间发生过100->101->100的变化
});
t1.start(); t2.start();
t1.join(); t2.join();
}
}
2. 解决方案:AtomicStampedReference
java
public class ABASolution {
private static AtomicStampedReference<Integer> stampedRef =
new AtomicStampedReference<>(100, 0);
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
int stamp = stampedRef.getStamp();
// A->B,版本号+1
stampedRef.compareAndSet(100, 101, stamp, stamp + 1);
stamp = stampedRef.getStamp();
// B->A,版本号再+1
stampedRef.compareAndSet(101, 100, stamp, stamp + 1);
});
Thread t2 = new Thread(() -> {
try { Thread.sleep(100); } catch (InterruptedException e) {}
int[] stampHolder = new int[1];
int currentValue = stampedRef.get(stampHolder);
int currentStamp = stampHolder[0];
// 虽然值还是100,但版本号变了,所以CAS失败!
boolean success = stampedRef.compareAndSet(
100, 200, currentStamp, currentStamp + 1
);
System.out.println("t2 CAS结果: " + success); // ❌ 失败!
});
t1.start(); t2.start();
t1.join(); t2.join();
}
}
五、JDK 8+ 的增强
1. 更高效的累积器(LongAdder/DoubleAdder)
java
// LongAdder - 高并发下性能远超AtomicLong
public class LongAdderDemo {
private final LongAdder adder = new LongAdder();
public void highConcurrencyScenario() {
// 原理:分段累加,减少竞争
// base + Cell[0] + Cell[1] + ... + Cell[n]
adder.increment(); // 快速累加
// 适用场景:大量并发写,偶尔读(如计数器、监控统计)
long sum = adder.sum(); // 读取时需要合并所有分段
}
// 内部结构
static class LongAdderInternal {
transient volatile Cell[] cells; // 分段数组
transient volatile long base; // 基础值
transient volatile int cellsBusy; // 扩容锁
// Cell类使用@Contended避免伪共享
@sun.misc.Contended
static final class Cell {
volatile long value;
Cell(long x) { value = x; }
}
}
}
2. 性能对比
java
// AtomicLong vs LongAdder 性能测试
public class PerformanceComparison {
public static void main(String[] args) {
// 场景:100个线程,每个累加100万次
// AtomicLong: ≈ 4500ms
// 原理:所有线程竞争同一个变量,大量CAS失败重试
// LongAdder: ≈ 800ms
// 原理:线程哈希到不同Cell,减少竞争,最后合并
}
}
3. 新的原子操作方法
java
public class JDK8NewFeatures {
private AtomicInteger atomic = new AtomicInteger(0);
public void newMethods() {
// 1. 函数式更新
atomic.getAndUpdate(x -> x * 2); // i = i * 2
atomic.updateAndGet(x -> x + 10); // i = i + 10
// 2. 累积操作
atomic.getAndAccumulate(5, (x, y) -> x + y); // i = i + 5
atomic.accumulateAndGet(3, (x, y) -> x * y); // i = i * 3
// 3. 懒设置(不保证立即对其他线程可见)
atomic.lazySet(100); // 性能更高,适合后续不用该值的场景
}
}
六、内存模型与可见性
1. volatile 的关键作用
java
public class AtomicMemoryModel {
// Atomic类中value字段必须用volatile修饰
private volatile int value;
// volatile保证:
// 1. 可见性:一个线程的修改对其他线程立即可见
// 2. 禁止指令重排序:防止编译器/CPU优化破坏原子性
// 3. happens-before:对volatile域的写入happens-before后续读取
}
2. 内存屏障实现
java
// Unsafe中的内存屏障操作(JDK 8+)
public class MemoryBarrierDemo {
private static final Unsafe unsafe = Unsafe.getUnsafe();
public void barrierOperations() {
// 1. 读屏障:确保屏障前的读操作先于屏障后的读操作完成
unsafe.loadFence();
// 2. 写屏障:确保屏障前的写操作先于屏障后的写操作完成
unsafe.storeFence();
// 3. 全屏障:同时包含读屏障和写屏障
unsafe.fullFence();
// CAS操作内部会自动插入内存屏障
}
}
七、CAS的局限性及解决方案
1. CAS的三大问题
java
public class CASLimitations {
// 1. ABA问题(已解决:AtomicStampedReference)
// 2. 循环时间长开销大
public void spinTooLong() {
// 高竞争下,大量线程CAS失败,不断重试
while (!cas()) {
// 长时间空转消耗CPU
}
}
// 3. 只能保证一个共享变量的原子操作
public void multipleVariables() {
// ❌ 无法原子地同时更新两个变量
// atomic1.compareAndSet(...) && atomic2.compareAndSet(...)
// 这不是原子操作!
// ✅ 解决方案:
// a. 使用AtomicReference包裹多个变量
// b. 使用锁
}
}
2. 自旋优化策略
java
// 自适应自旋锁(JVM实现)
public class AdaptiveSpinning {
// JVM根据历史成功率动态调整自旋次数
// 1. 如果上次CAS成功,则增加自旋次数
// 2. 如果上次CAS失败,则减少自旋次数
// 3. 可能直接挂起线程,避免CPU空转
}
八、实战应用示例
1. 高性能计数器
java
// 根据并发度选择不同的原子类
public class SmartCounter {
private final boolean highContention;
private final Object counter;
public SmartCounter(boolean highContention) {
this.highContention = highContention;
this.counter = highContention ? new LongAdder() : new AtomicLong();
}
public void increment() {
if (highContention) {
((LongAdder) counter).increment();
} else {
((AtomicLong) counter).incrementAndGet();
}
}
public long get() {
return highContention ?
((LongAdder) counter).sum() :
((AtomicLong) counter).get();
}
}
篇幅限制下面就只能给大家展示小册部分内容了。整理了一份核心面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafc
需要全套面试笔记及答案
【点击此处即可/免费获取】
2. 无锁栈实现
java
// 使用AtomicReference实现无锁栈
public class LockFreeStack<T> {
private static class Node<T> {
final T value;
Node<T> next;
Node(T value) { this.value = value; }
}
private final AtomicReference<Node<T>> top = new AtomicReference<>();
public void push(T value) {
Node<T> newHead = new Node<>(value);
Node<T> oldHead;
do {
oldHead = top.get();
newHead.next = oldHead;
} while (!top.compareAndSet(oldHead, newHead));
}
public T pop() {
Node<T> oldHead, newHead;
do {
oldHead = top.get();
if (oldHead == null) return null;
newHead = oldHead.next;
} while (!top.compareAndSet(oldHead, newHead));
return oldHead.value;
}
}
九、总结与最佳实践
1. 原子类选择指南
| 场景 | 推荐类 | 原因 |
|---|---|---|
| 低竞争计数器 | AtomicInteger/Long |
简单直接 |
| 高竞争计数器 | LongAdder/DoubleAdder |
分段减少竞争 |
| 对象引用更新 | AtomicReference |
原子更新引用 |
| 需要版本控制 | AtomicStampedReference |
解决ABA问题 |
| 批量对象字段更新 | Atomic*FieldUpdater |
节省内存 |
2. 使用注意事项
java
public class BestPractices {
// ✅ 正确做法
public void goodPractice() {
// 1. 使用static final修饰
private static final AtomicInteger COUNTER = new AtomicInteger();
// 2. 考虑使用LongAdder替代AtomicLong(高并发写)
// 3. 避免过度使用:非竞争场景用普通变量
// 4. 复杂复合操作仍需锁
if (atomic.get() > threshold) {
synchronized (this) { // 需要原子检查+操作
if (atomic.get() > threshold) {
doSomething();
atomic.decrementAndGet();
}
}
}
}
// ❌ 错误做法
public void badPractice() {
// 1. 频繁创建Atomic对象(应在类级别共享)
// 2. 用Atomic实现复杂业务逻辑(应用锁)
// 3. 忽略ABA问题(涉及资金、状态等关键数据)
}
}
3. 性能优化建议
-
减少竞争 :使用
LongAdder代替AtomicLong -
避免伪共享 :使用
@Contended注解(JDK 8+) -
合理使用lazySet:不需要立即可见性的场景
-
监控CAS成功率:高失败率说明竞争激烈,需优化
核心原理总结 :Atomic原子类通过 CAS + volatile + Unsafe 实现了高效的无锁并发,是现代并发编程的基石。理解其原理有助于在合适场景选择合适工具,构建高性能并发系统。