【CAS】全称为 Compare and swap,即"比较并交换",相当于通过一个原子操作,同时完成"读取内存,比较是否相等,修改内存"这三个步骤,本质上需要 CPU 指令支持~
CAS 是并发编程中一个重要的概念,相当于是打开了新世界的大门,可以在不加锁的情况下保证线程安全,从而减少线程之间的竞争和开销,通常用于无锁编程,本文将结合 Java 多线程操作讲解 CAS 机制,我们一起来看看吧!
1.1 CAS 具体步骤
CAS 机制的基本思想是,先比较内存 V 中的值与寄存器 A 中的值(旧的预期值),是否相等,如果相等,则将寄存器 B 中的值(需要修改的新值)写入内存中,如果不相等,则不作任何操作,这整个过程是原子的~
CAS 涉及到以下三个操作,假设内存中的原数据V,旧的预期值A,需要修改的新值B
- 读取内存值:将需要修改的值从主内存中读入本地线程缓存或工作内存
- 比较并尝试交换:比较 A 与 V 是否相等,如果比较相等,将 B 写入 V,如果不相等,不作任何操作
- 返回操作结果:如果成功更新了值,则返回成功标志或新值,如果失败更新,则返回失败标志或当前内存中的值
1.2 CAS 伪代码
如果把 CAS 想象成一个函数,可以得到 CAS 的伪代码,但是下述的伪代码,并不是真正的 CAS 代码,事实上,CAS 操作是一条由 CPU 硬件支持、原子的硬件指令,而这一条指令就可以完成下述这一段代码的功能(CAS 本身就是对应一条 CPU 指令,不可拆分的最小单位,此时,CAS 中比较和交换动作是没办法再拆分的)
boolean CAS(address,expectValue,swapValue) {
if(&address == expectedValue) {
&address = swapValue;
return true;
}
return false;
}
图解如下:
可以知道,上述这一段代码,非原子,运行过程中可能随着线程的调度有概率产生线程安全问题,而原子指令不会有线程安全问题~
同时,CAS也不会有内存可见性的问题,内存可见性是编译器把一系列指令进行调整,把读内存指令调整成直接读寄存器的指令,效率大大提升,可能会误判,从而产生 bug,但是 CAS 本身就是指令级别读取内存的操作,因此,不会有内存可见性带来的线程安全问题
即 CAS 可以不加锁也能一定程度保证线程安全!这样就可以基于 CAS 机制,实现一系列操作!