🔍 CAS机制与原子类源码解析:从Unsafe到LongAdder
🧠前言:并发控制中的原子性难题
在并发编程中,线程安全始终是核心难题。尤其是在无锁并发(Lock-Free)场景下,如何保证变量操作的原子性?
Java 从 JDK1.5 开始引入了 java.util.concurrent.atomic 原子类,为开发者提供了基于 CAS(Compare-And-Swap) 的非阻塞同步机制,避免传统 synchronized 带来的性能瓶颈。
本文将从底层原理出发,深入解析 CAS 机制、Unsafe 类实现、JUC 原子类的设计架构,并重点剖析 LongAdder 的高并发优化方案。
文章目录
一、并发原子性难题
💡 原子性问题本质
⚠️ 传统方案缺陷
方案 | 问题 | 影响 |
---|---|---|
synchronized | 重量级锁开销 | 上下文切换成本高 |
volatile | 不保证原子性 | 复合操作不安全 |
Lock API | 竞争激烈时性能下降 | 吞吐量降低 |
二、CAS机制深度解析
💡 CAS操作原理
⚙️ CPU指令支持
; x86架构的CAS指令
lock cmpxchg [mem], reg
; lock前缀保证原子性
; cmpxchg比较并交换
⚠️ ABA问题与解决方案
// ABA问题示例
AtomicInteger atomic = new AtomicInteger(100);
Thread t1 = new Thread(() -> {
atomic.compareAndSet(100, 101); // A->B
atomic.compareAndSet(101, 100); // B->A
});
Thread t2 = new Thread(() -> {
sleep(100);
atomic.compareAndSet(100, 102); // 成功但中间有变化
});
// 解决方案:AtomicStampedReference
AtomicStampedReference<Integer> ref = new AtomicStampedReference<>(100, 0);
ref.compareAndSet(100, 102, 0, 1); // 版本号验证
三、Unsafe类源码剖析
💡 Unsafe核心能力
⚙️ CAS底层实现
public final class Unsafe {
// CAS原子操作
public final native boolean compareAndSwapInt(
Object o, long offset, int expected, int x);
// 获取字段偏移量
public long objectFieldOffset(Field f) {
// 返回字段在对象内存中的偏移地址
}
}
// AtomicInteger使用示例
public class AtomicInteger {
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;
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) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
}
🔧 绕过限制获取Unsafe
// 反射获取Unsafe实例
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
Unsafe unsafe = (Unsafe) theUnsafe.get(null);
四、J.U.C原子类架构设计
💡 原子类体系
⚙️ AtomicInteger源码解析
public class AtomicInteger {
private volatile int value;
public final int get() {
return value; // volatile读
}
public final void set(int newValue) {
value = newValue; // volatile写
}
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
// CAS自增
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
}
🔄 getAndAddInt实现
// Unsafe中的循环CAS
public final int getAndAddInt(Object o, long offset, int delta) {
int v;
do {
v = getIntVolatile(o, offset); // 读取当前值
} while (!compareAndSwapInt(o, offset, v, v + delta));
return v;
}
五、LongAdder性能优化
💡 高并发下AtomicLong瓶颈
⚙️ LongAdder分治策略
🔍 LongAdder源码解析
public class LongAdder {
transient volatile Cell[] cells;
transient volatile long base;
public void add(long x) {
Cell[] as; long b, v; int m; Cell a;
// 尝试更新base
if ((as = cells) != null || !casBase(b = base, b + x)) {
boolean uncontended = true;
// 获取线程hash
int h = Thread.currentThread().hashCode();
// 定位Cell
if (as == null || (m = as.length - 1) < 0 ||
(a = as[h & m]) == null ||
!(uncontended = a.cas(v = a.value, v + x)))
longAccumulate(x, null, uncontended);
}
}
public long sum() {
Cell[] as = cells; Cell a;
long sum = base;
if (as != null) {
for (Cell cell : as) {
if (cell != null)
sum += cell.value;
}
}
return sum;
}
}
📊 性能对比数据
线程数 | AtomicLong(ops/ms) | LongAdder(ops/ms) | 提升倍数 |
---|---|---|---|
1 | 50,000 | 45,000 | 0.9x |
4 | 15,000 | 80,000 | 5.3x |
16 | 3,000 | 150,000 | 50x |
64 | 800 | 180,000 | 225x |
六、实战场景与选型指南
💡 原子类选型决策树
⚠️ 使用禁忌场景
场景 | 问题 | 替代方案 |
---|---|---|
复合操作 | 非原子性 | synchronized/Lock |
依赖顺序 | ABA问题 | AtomicStampedReference |
严格一致性 | LongAdder弱一致性 | AtomicLong |
频繁读操作 | LongAdder求和开销 | AtomicLong |
⚡️ 高并发计数器实现
// 低并发场景
private final AtomicInteger counter = new AtomicInteger(0);
public void increment() {
counter.incrementAndGet();
}
// 高并发场景
private final LongAdder adder = new LongAdder();
public void increment() {
adder.increment();
}
public long getCount() {
return adder.sum();
}
// 分布式场景
private final RedisAtomicLong redisCounter =
new RedisAtomicLong("counter", redisTemplate.getConnectionFactory());
public void increment() {
redisCounter.incrementAndGet();
}
七、总结与最佳实践
🏆 CAS机制核心价值
📝 最佳实践清单
-
选型原则:
- 低竞争:AtomicInteger/AtomicLong
- 高竞争:LongAdder
- 对象引用:AtomicReference
- 版本控制:AtomicStampedReference
-
性能优化:
- 避免CAS热点:LongAdder分治
- 减少CAS重试:退避算法
- 控制ABA问题:版本号机制
-
错误规避:
- 复合操作需加锁
- 严格一致性用AtomicLong
- 避免LongAdder频繁sum()
⚡️ 高并发场景建议
// 使用LongAdder作为全局计数器
public class GlobalCounter {
private static final LongAdder counter = new LongAdder();
public static void increment() {
counter.increment();
}
public static long get() {
return counter.sum();
}
}
// 使用AtomicStampedReference解决ABA
public class BankAccount {
private AtomicStampedReference<Integer> balance =
new AtomicStampedReference<>(100, 0);
public boolean transfer(int amount) {
int[] stamp = new int[1];
while (true) {
int current = balance.get(stamp);
int newStamp = stamp[0] + 1;
if (balance.compareAndSet(current, current + amount, stamp[0], newStamp)) {
return true;
}
}
}
}
🔧 监控与调优工具
# 查看CAS成功率
-XX:+PrintAssembly
-XX:PrintIntrinsicStatistics
# 性能分析
jstat -gcutil <pid> 1000
jcmd <pid> PerfCounter.print | grep cas
理解比使用更重要:深入理解CAS机制才能用好原子类
场景决定选型:没有最好的方案,只有最适合的
监控是生命线:没有指标就不要谈优化
记住:CAS不是银弹,而是工具箱中的利器