无锁算法-CAS

    要实现无锁(lock-free)的非阻塞算法有多种实现方法,其中CAS(Compare and Swap)是一种有名的无锁算法。  

     CAS(Compare and Swap),即比较并替换,实现并发算法时常用到的一种技术,是用乐观锁技术实现的一种无锁(lock-free)算法。当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试。CAS有3个操作数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做。

    wikipedia中对于CAS的定义为:
        1、是一种多线程中的原子操作
        2、类似于乐观锁,只有当读取的值和预期值相等时才进行赋新值
        3、返回结果必须表明是否成功
    CAS在JVM中的实现(Atomic类):
    例如AtomicInteger中部分代码:
   
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;

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

private volatile int value;

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;
}
    1、Unsafe是CAS的核心类,Java无法直接访问底层操作系统,而是通过本地(native)方法来访问。Unsafe类就是这样一个native方法集合,它提供了硬件级别的原子操作。
    2、valueOffset表示的是变量值在内存中的偏移地址,因为Unsafe就是根据内存偏移地址获取数据的原值的。
    3、value是用volatile修饰的,保证了写之后的可见性
    4、getAndAddInt是完成原子操作最重要的方法
    
    CAS的缺点:
    1、value区被大量线程同时尝试修改时,getAndAddInt中循环可能会一定的延迟,导致对性能产生影响
    2、ABA问题,如果初始值为A线程读到为1,B线程修改为2然后又修改为1,那A线程读到的依然是1会认为值没被修改过,解决该问题常见的办法是加1个版本号,例如AtomicStampedReference的实现

    3、只能保证一个共享变量的原子操作,对多个共享变量操作时,循环CAS就无法保证操作的原子性。解决:多个变量合并成一个共享变量操作或放在一个对象里如AtomicReference

    推荐文章:深入浅出CAS

你可能感兴趣的:(无锁算法-CAS)