CAS - Compare And Swap

特性

存在的问题

  • ABA 问题
    • A 被改成 B, 然后 B 又被改成 A, 值没变, 但是被别人修改过了
    • AtomicStampedReference, 增加了 stamp 版本号, 可以解决
  • 循环时间长开销大 (忙等待)
    • CAS 经常会用到自旋操作来进行重试
  • 只能保证一个共享变量的原子操作
    • AtomicReference 类, 保证引用对象之间的原子性

CAS 自旋

CAS 本身不自旋, 通常情况下, CAS 操作都会采用自旋的方式. 当 CAS 失败时,会重新尝试执行 CAS 操作, 直到操作成功或达到最大重试次数为止.

// Unsafe#getAndAddInt 原子地获取并增加整数值
public final int getAndAddInt(Object o, long offset, int delta) {
    int v;
    do {
        // 以 volatile 方式获取对象 o 在内存偏移量 offset 处的整数值
        v = getIntVolatile(o, offset);
    } while (!compareAndSwapInt(o, offset, v, v + delta));
    // 返回旧值
    return v;
}

CAS+自旋实现单例

实际工作中不要用这种方法

public class Singleton {
    private static final AtomicReference<Singleton> INSTANCE =
		new AtomicReference<Singleton>(); 
 
    private Singleton() {}
 
    public static Singleton getInstance() {
        for (;;) {
            Singleton singleton = INSTANCE.get();
            if (null != singleton) {
                return singleton;
            }
 
            singleton = new Singleton();
            if (INSTANCE.compareAndSet(null, singleton)) {
                return singleton;
            }
        }
    }
}

See Also