美文网首页
CAS: compare and swap

CAS: compare and swap

作者: 字母数字或汉字 | 来源:发表于2016-10-01 22:10 被阅读226次

    这是一条现代 CPU 的硬件同步原语,即由 CPU 保证其原子性。

    需要提供三个参数:内存位置、预期值、新值。如果内存位置的值与预期值相匹配,那么处理器会自动将该位置更新为新值,否则不做任何操作。

    Java 通过 JNI ( Java Native Interface ) 调用 C/C++ 方法来执行 CPU 的 CAS 指令,完成该任务。

    这是 Java 的 J.U.C. ( java.util.concurrent ) 包实现原子操作的基础。

    我们来举个例子讲一讲。

    单线程下可以这种操作:

    if (a == b) a++;
    

    但多线程下我们要么加锁,要么使用“自旋 CAS”(自旋 == 忙等待):

    
    volatile int value;
    
    for (;;) {
        int curValue = get();  
        if (compareAndSet(curValue, newValue))  
            return curValue;  
    }
    

    JNI 调用长这样:

    public final boolean compareAndSet(int expect, int update) {   
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
    }
    

    一些问题

    ABA 问题

    CAS 不能检测 ABA 问题,即某变量虽然被多次修改(A->B->A),却最终改回了期望值,这将导致 CAS 成功,实际上该变量被修改过你却不知道!在这种情况下,考虑对每个操作添加版本号计数来避免。

    从 Java 1.5开始 atomic 包提供了 AtomicStampedReference 类来解决 ABA 问题。这个类的 compareAndSet 方法首先检查当前引用是否等于预期引用,并且当前标志是否等于预期标志,如果全部相等,则以原子方式将该引用和该标志的值设置为给定的更新值。

    关于ABA问题参考文档: http://blog.hesey.net/2011/09/resolve-aba-by-atomicstampedreference.html

    只能保证一个共享变量的原子操作

    有一个取巧的办法,就是把多个共享变量合并成一个共享变量来操作。从 Java 1.5 开始提供了 AtomicReference 类来保证引用对象之间的原子性,可以把多个变量放在一个对象里来进行 CAS 操作。

    资源竞争严重时慎用

    自旋 CAS 在资源竞争严重时,会导致频繁失败,浪费 CPU 时间,耗尽分配给它的时间片。Java 1.6 之后改进过的 synchronized 原语在此时能获得更好的性能。

    相关文章

      网友评论

          本文标题:CAS: compare and swap

          本文链接:https://www.haomeiwen.com/subject/zwgryttx.html