原子类 CAS 与 AtomicInteger 底层实现
原子类 CAS 与 AtomicInteger 底层实现
一、CAS(Compare And Swap)原理
CAS 是一种无锁(Lock-Free)并发控制机制,通过硬件指令保证操作的原子性。其核心思想是:先比较内存中的值是否与预期值一致,若一致则更新为新值,否则重试或放弃。
1. CAS 操作步骤
- 读取内存值:获取当前内存位置的值
V。 - 比较预期值:检查
V是否等于预期值A。 - 更新为新值:若相等,将内存值更新为
B;否则不操作。 - 返回结果:返回操作是否成功(布尔值)或内存当前值。
2. CAS 硬件支持
- x86 架构:通过
CMPXCHG指令实现。 - ARM 架构:通过
LDREX和STREX指令对实现。
3. CAS 的优缺点
- 优点:
- 无锁:减少线程阻塞,提升并发性能。
- 轻量级:无需上下文切换。
- 缺点:
- ABA 问题:值从
A → B → A,CAS 无法感知中间变化。 - 自旋开销:高竞争下频繁重试可能浪费 CPU 资源。
- 单变量限制:只能保证单个变量的原子性。
- ABA 问题:值从
二、AtomicInteger 底层实现
AtomicInteger 是 Java 提供的原子整数类,基于 CAS 实现线程安全的原子操作。
1. 核心字段与初始化
public class AtomicInteger implements Serializable {
private static final long serialVersionUID = 6214790243416807050L;
// 使用 volatile 保证可见性
private volatile int value;
// Unsafe 类提供 CAS 底层操作
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset; // value 字段的内存偏移量
static {
try {
// 获取 value 字段在对象内存中的偏移量
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
}
2. 核心方法解析
getAndIncrement():原子递增并返回旧值。
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
Unsafe 的 getAndAddInt:
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;
}
compareAndSet():CAS 更新值。
public final boolean compareAndSet(int expect, int update) {
return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
}
3. 执行流程
以 incrementAndGet() 为例:
- 读取当前值
current。 - 计算新值
next = current + 1。 - 调用
compareAndSwapInt尝试更新:- 成功:返回
next。 - 失败:自旋重试,直到成功。
- 成功:返回
graph TD
A[开始] --> B[读取当前值 current]
B --> C[计算新值 next = current + 1]
C --> D{CAS 更新 current → next?}
D -- 成功 --> E[返回 next]
D -- 失败 --> B
三、解决 ABA 问题
ABA 问题指变量值经历了 A → B → A 的变化,CAS 无法感知中间状态。解决方案:
1. 版本号(Stamp)机制
通过 AtomicStampedReference 维护值和版本号的双重校验。
AtomicStampedReference<Integer> ref = new AtomicStampedReference<>(100, 0);
// 更新时检查值和版本号
boolean success = ref.compareAndSet(100, 200, 0, 1);
2. 时间戳或计数器
每次更新递增版本号,确保值变化的唯一性。
四、AtomicInteger 的性能优化
1. 对比锁机制
- synchronized:通过监视器锁实现,竞争激烈时线程阻塞,上下文切换开销大。
- AtomicInteger:基于 CAS 自旋,无锁,适用于低竞争场景。
2. 高并发场景优化
- LongAdder:Java 8 引入,采用分段 CAS(Cell 数组分散竞争),适合高并发写入。
- 性能对比:
场景 AtomicInteger LongAdder 低并发 更优 稍差(初始化开销) 高并发 差(CAS 竞争) 更优
五、其他原子类
Java 提供多种原子类,原理与 AtomicInteger 类似:
- AtomicLong:原子长整型操作。
- AtomicBoolean:原子布尔值操作。
- AtomicReference:原子对象引用操作。
- AtomicIntegerArray:原子整数数组操作。
六、总结
- CAS 是原子类的基石,通过硬件指令实现无锁并发。
- AtomicInteger 利用
Unsafe类的 CAS 操作保证线程安全,核心方法是自旋 + CAS。 - ABA 问题 可通过版本号或时间戳解决。
- 在高并发场景下,优先选择
LongAdder或LongAccumulator。
// 示例:AtomicInteger 的线程安全计数
public class Counter {
private AtomicInteger count = new AtomicInteger(0);
public void increment() {
count.incrementAndGet();
}
public int get() {
return count.get();
}
}

348

被折叠的 条评论
为什么被折叠?



