并发编程中的 CAS 原理知道吗?

PassJava (佳必过) 项目全套学习教程连载中,关注公众号悟空聊架构第一时间获取。

文档在线地址: www.passjava.cn

原子整型类 AtomicInteger 的 getAndIncrement 方法就用到 CAS。

比如这一段代码:

atomicInteger.compareAndSet(10, 20);

调用 atomicInteger 的 CAS 方法,先比较当前变量 atomicInteger 的值是否是10,如果是,则将变量的值设置为20。

  • CAS 的全称:Compare-And-Swap(比较并交换)。比较变量的现在值与之前的值是否一致,若一致则替换,否则不替换。

  • CAS 的作用:原子性更新变量值,保证线程安全。

  • CAS 指令底层代码:需要有三个操作数,变量的当前值(V),旧的预期值(A),准备设置的新值(B)。

  • CAS 指令执行条件:当且仅当 V=A 时,处理器才会设置 V=B,否则不执行更新。

  • CAS 的返回值:V 的之前值。

  • CAS 处理过程:原子操作,执行期间不会被其他线程中断,线程安全。

  • CAS 并发原语:体现在 Java 语言中 sun.misc.Unsafe 类的各个方法。调用 UnSafe 类中的 CAS 方法,JVM 会帮我们实现出 CAS 汇编指令,这是一种完全依赖于硬件的功能,通过它实现了原子操作。由于 CAS 是一种系统原语,原语属于操作系统用于范畴,是由若干条指令组成,用于完成某个功能的一个过程,并且原语的执行必须是连续的,在执行过程中不允许被中断,所以 CAS 是一条 CPU 的原子指令,不会造成所谓的数据不一致的问题,所以 CAS 是线程安全的。

CAS 带来的问题:

1)频繁出现自旋,循环时间长,开销大(因为执行的是do while,如果比较不成功一直在循环,最差的情况,就是某个线程一直取到的值和预期值都不一样,这样就会无限循环)

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

  • 当对一个共享变量执行操作时,我们可以通过循环CAS的方式来保证原子操作

  • 但是对于多个共享变量操作时,循环CAS就无法保证操作的原子性,这个时候只能用锁来保证原子性。

作者简介:悟空,8年一线互联网开发和架构经验,用故事讲解分布式、架构设计、Java 核心技术。《JVM性能优化实战》专栏作者,开源了《Spring Cloud 实战 PassJava》项目,公众号:悟空聊架构

悟空的开源项目

https:///Jackson0714/PassJava-Platform