001-Java基础-CAS

什么是CAS

CAS全称compare-and-swap(比较并交换),是一系列操作的集合,包括:

  • 获取当前值
  • 进行一些运算
  • 利用CAS指令进行更新。如果当前值未变,则更新成功;否则更新失败或者进行重试。

CAS出现的目的是为了在多线程编程中实现不被打断的数据操作,从而避免由于多线程操作同一数据导致的数据不一致问题。

Syncrhonized、ReentrantLock可以看做是悲观锁,而CAS则是乐观锁。

CAS的实现原理

CAS依赖于CPU提供的特定指令,在不同体型结构中也存在明显区别。

Java如何实现CAS操作

首先,可以通过Unsafe类实现CAS操作,例如AtomicInteger类,源码如下:

private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;
private volatile int value;

static {
    try {
        valueOffset = unsafe.objectFieldOffset
            (AtomicInteger.class.getDeclaredField("value"));
    } catch (Exception ex) { throw new Error(ex); }
}

public AtomicInteger(int initialValue) {
    value = initialValue;
}
  
public final int incrementAndGet() {
    return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}  

数值保存在value变量中,通过volatile保证可见性,在incrementAndGet()方法里,通过Unsafe类的getAndAddInt()进行CAS操作。

Unsafe类的源码如下:

public final int getAndAddInt(Object var1, long var2, int var4) {
    int var5;
    do {
        var5 = this.getIntVolatile(var1, var2);
    } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

    return var5;
}

除了Unsafe,Java还提供了两种公共API实现CAS操作。

  • java.util.concurrent.atomic.AtomicLongFieldUpdater类。
  • Variable Handle API。

ABA问题

CAS不是万能的,在某些特殊场景下也会出现问题,例如著名的ABA问题,基本过程:

  1. 进程P1读取了一个数值A。
  2. P1被挂起(时间片耗尽、中断等),进程P2开始执行。
  3. P2修改数值A为数值B,然后又修改回A
  4. P1被唤醒,比较后发现数值A没有变化,程序继续执行。

详细的说明请参考下面的文章: https://zh.wikipedia.org/wiki/比较并交换

上篇001-Java基础-内存区域划分
下篇001-Java基础-锁