原子类 CAS 与 AtomicInteger 底层实现


原子类 CAS 与 AtomicInteger 底层实现


一、CAS(Compare And Swap)原理

CAS 是一种无锁(Lock-Free)并发控制机制,通过硬件指令保证操作的原子性。其核心思想是:先比较内存中的值是否与预期值一致,若一致则更新为新值,否则重试或放弃

1. CAS 操作步骤
  1. 读取内存值:获取当前内存位置的值 V
  2. 比较预期值:检查 V 是否等于预期值 A
  3. 更新为新值:若相等,将内存值更新为 B;否则不操作。
  4. 返回结果:返回操作是否成功(布尔值)或内存当前值。
2. CAS 硬件支持
  • x86 架构:通过 CMPXCHG 指令实现。
  • ARM 架构:通过 LDREXSTREX 指令对实现。
3. CAS 的优缺点
  • 优点
    • 无锁:减少线程阻塞,提升并发性能。
    • 轻量级:无需上下文切换。
  • 缺点
    • ABA 问题:值从 A → B → A,CAS 无法感知中间变化。
    • 自旋开销:高竞争下频繁重试可能浪费 CPU 资源。
    • 单变量限制:只能保证单个变量的原子性。

二、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() 为例:

  1. 读取当前值 current
  2. 计算新值 next = current + 1
  3. 调用 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 数组分散竞争),适合高并发写入。
  • 性能对比
    场景AtomicIntegerLongAdder
    低并发更优稍差(初始化开销)
    高并发差(CAS 竞争)更优

五、其他原子类

Java 提供多种原子类,原理与 AtomicInteger 类似:

  • AtomicLong:原子长整型操作。
  • AtomicBoolean:原子布尔值操作。
  • AtomicReference:原子对象引用操作。
  • AtomicIntegerArray:原子整数数组操作。

六、总结
  • CAS 是原子类的基石,通过硬件指令实现无锁并发。
  • AtomicInteger 利用 Unsafe 类的 CAS 操作保证线程安全,核心方法是自旋 + CAS。
  • ABA 问题 可通过版本号或时间戳解决。
  • 在高并发场景下,优先选择 LongAdderLongAccumulator
// 示例:AtomicInteger 的线程安全计数
public class Counter {
    private AtomicInteger count = new AtomicInteger(0);
    
    public void increment() {
        count.incrementAndGet();
    }
    
    public int get() {
        return count.get();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值