欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

CAS: compare and swap

程序员文章站 2022-07-14 08:54:45
...

这是一条现代 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 原语在此时能获得更好的性能。

上一篇: Singleton

下一篇: jfinal+maven+beetl