CAS原则

compare and swap,比较并替换

    思路:三个参数,一个为当前内存值V,旧的预期值为A,即将更新的值为 B。

    当且仅当V=A时,将内存值修改为B并返回true,否则什么都不做返回false

public int a = 1;

public boolean compareAndSwapInt(int b) {

    if (a == 1) {

        a = b;

        return true;

    }

    return false;

}

看看AtomicInteger如何实现并发下的累加操作

假设线程A和线程B同时执行getAndAdd操作(分别跑在不同CPU上):

1. AtomicInteger里面的value原始值为3,即主内存中AtomicInteger的value为3,根据Java内存模型,线程A和线程B各自持有一份value的副本,值为3。

2. 线程A通过getIntVolatile(var1, var2)拿到value值3,这时线程A被挂起。

3. 线程B也通过getIntVolatile(var1, var2)方法获取到value值3,运气好,线程B没有被挂起,并执行compareAndSwapInt方法比较内存值也为3,成功修改内存值为2。

4. 这时线程A恢复,执行compareAndSwapInt方法比较,发现自己手里的值(3)和内存的值(2)不一致,说明该值已经被其它线程提前修改过了,那只能重新来一遍了。

5. 重新获取value值,因为变量value被volatile修饰,所以其它线程对它的修改,线程A总是能够看到,线程A继续执行compareAndSwapInt进行比较替换,直到成功。

intel手册对lock前缀的说明如下:

1. 确保后续指令执行的原子性。

在Pentium及之前的处理器中,带有lock前缀的指令在执行期间会锁住总线,使得其它处理器暂时无法通过总线访问内存,很显然,这个开销很大。在新的处理器中,Intel使用缓存锁定来保证指令执行的原子性,缓存锁定将大大降低lock前缀指令的执行开销。

2. 禁止该指令与前面和后面的读写指令重排序。

3. 把写缓冲区的所有数据刷新到内存中。

上面的第2点和第3点所具有    的内存屏障效果,保证了CAS同时具有volatile读和volatile写的内存语义。

CAS缺点

CAS存在一个很明显的问题,即ABA问题。

问题:如果变量V初次读取的时候是A,并且在准备赋值的时候检查到它仍然是A,那能说明它的值没有被其他线程修改过了吗?

如果在这段期间曾经被改成B,然后又改回A,那CAS操作就会误认为它从来没有被修改过。针对这种情况,java并发包中提供了一个带有标记的原子引用类AtomicStampedReference,它可以通过控制变量值的版本来保证CAS的正确性

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Java8张图 11、字符串不变性 12、equals()方法、hashCode()方法的区别 13、...
    Miley_MOJIE阅读 9,125评论 0 11
  • 在并发的情况下,Java主要靠synchronized和lock来保证同步,已解决多线程下的线程不安全问题,锁虽然...
    激情的狼王阅读 7,061评论 3 11
  • 转载:并发-CAS原则 1.java内存模型图: 每个线程单独有一份来自内存的变量拷贝,彼此之间的操作是不可见的。...
    小小少年Boy阅读 5,818评论 0 1
  • 本文首发:WindCoder 什么是CAS? 全称:Compare And Swap,翻译为比较并替换。 CAS机...
    蜜汁炒酸奶阅读 4,079评论 0 1
  • 前言 CAS(compare and swap, 比较并交换),是原子操作的一种,可用于在多线程编程中实现不被打断...
    草捏子阅读 6,099评论 0 4