第8章 CAS教程
2.3 CAS
2.3.1 CAS是什么?
原子操作新思路
什么是原子操作?
原子操作是执行过程中不被CPU中断的操作,原子操作不会出现多线程交替执行。
比如:
b++、a+=2不具有原子性,多线程在执行时会存在多线程交替执行。
int a=0 具有原子性。
如何将非原子操作实现原子操作?
使用synchronized即可实现:
synchronized(obj){
b++;
}
synchronized(obj){
a+=2;
}b++代码处地临界区中被同步锁保护,多线程执行临界区的代码只能同步执行即串行执行。
有关synchronized实现原子操作的内容可以参考“原子性”章节。
synchronized同步锁也称为悲观锁,它认为总会有线程修改另一个线程的数据造成线程不安全,它将临界区加锁控制,多线程只允许串行执行,这样就保证了一个线程在执行代码的同时不会有线程去交替执行,但是使用悲观锁的性能不高。
有没有一种相比悲观锁方案性能高的实现原子操作的方案呢?
CAS是一种无锁技术,也被称为乐观锁技术。乐观锁认为总是不会有线程去修改另一个线程的数据,所以它在操作时无需使用同步锁即可实现原子操作。CAS依赖CPU的CAS指令在更新数据前先判断数据是否被其它线程修改,如果没有修改则更新。
CAS是什么?
CAS的全称是Compare And Set,即比较并设置(也称为Compare And Swap即比较并交换),CAS从名称上是两个操作(一个比较 一个设置),但它是原子操作,底层由CPU指令支持,将比较和设置实现原子操作。
下面的例子说明 了CAS的操作过程:
下边通过一个例子说明CAS的过程,开发中++操作用的较多,下图是CAS实现++的原子操作:

1、取出期望值,比如求a++,首先取a此时的内存值0。
2、计算目标值,计算a+1的值为1,注意此值是基于a等于0计算得到。
3、调用CAS指令。
4、CAS指令:取出a的当前值和期望值比较,如果相等则用目标值替换当前值。
如果a的期望值与当前值不一致则说明有其它线程将a的值已经更改,转到第一步重新执行。
上图中橙色为CAS指令执行过程,根据CAS的过程可知正确使用CAS的方法如下:
while(true){
//取出期望值
//计算目标值
//调用CAS方法
//判断如果操作成功则退出,否则继续下一轮循环
if(CAS方法(...)){
break;
}
}所以:
CAS操作共需要两个参数:期望值、目标值,目标值是基于期望值计算得出,CAS指令执行时会取出当前内存值与期望值比较如果相等则用目标值更新当前值。
CAS应用场景
CAS是一种无锁实现原子操作的技术,也被称为乐观锁,对于并发高且写多的场景来说,CAS失败的概率很大,会不断的循环执行,导致CPU开销增加。CAS的这种不断循环尝试的过程叫自旋,它会不断重试直到操作成功为止,所以CAS适合读多写少的场景。比如:成绩更正,成绩录入完成后因录入错误需要更正的频率是很少的。
悲观锁适用并发量不大且接受一定延迟的场景,比如:订单退费,非双十一时订单退费的并发量相比下单的并发量少很多,且退费有一定的延迟用户可以接受。
CAS性能
CAS采用无锁技术,其性能高于synchronized同步锁,原因如下:
1、synchronized同步锁使线程串行执行,没有获得锁的线程会进入等待队列阻塞,阻塞解除发生线程切换,上下文切换会耗费性能。
2、通过上边的入门程序可知CAS操作不成功会不断重试直到成功为止,CAS大大减少线程上下文切换的几率。
注意:synchronized从jdk6开始优化,其性能有了很大的提高,所以不要认为synchronized有多么的差,在实际开发要根据应用场景选用适合的技术方案。
请免费关注 预见猿份 公众号,发送:yjoffer.com,获取解锁密码
微信扫码关注关注公众号回复获取密码后,在下方输入并点击解锁,本机后续再读无需重复输入。
