什么是CAS机制
CAS即CompareAndSet被称之为无锁优化,从设计思想来说CAS属于乐观锁
CAS原理
int count = 0;
compareAndSet(count, 1, 2)
此代码块需要对count执行加1操作此处的count就相当于下图中的valueOffset,1就相当expect,2就相当于update,如果expect等于valueOffset才会将count设为2也就是图中的update,如果不相等则重新预估expect的值直到成功为止,这个不断预估expect值的过程称之为自旋,是在内存中进行的。
为什么要进行count是否等于expect的比较呢?我们可以想象一种 高并发的场景,有多个线程需要同时对count进行加1操作如果线程1一开始获取到了count的值为1,此时的expect值为1,update为2,当线程1还没执行完对count的加1操作时CPU分配给线程1的时间片到了,这个时候线程2进来了执行了对count的一个自增操作count变为了2,当再次轮到线程1操作时如果不进行valueOffset是否等于expect的操作就会导致count重新变回1,这样就出现了线程不安全的问题。
CAS机制代码演示
ABA问题以及解决方案
- 线程1获取到如下的值,CPU使用时间片到了,进入到了等待状态
- 这时线程2获得CPU资源将值修改为10
- 接着又将值修改回到3
- 接着线程1又获取到了CPU资源,这是对于线程1来说valueOffset相当于没有变,这就是ABA问题
- 如果valueOffset为整数ABA问题是没有影响的但是当我们把valueOffset引申为对象,这就不一定了因为对象在这个变来变去的过程中可能改变了其中属性的值,如何解决ABA问题,添加一个版本号version就能有效的解决,每进行一次操作时就对version进行加1操作,每次操作前同时进行version的校验
CAS机制的缺点
- CPU开销较大
在并发量比较高的情况下,如果许多线程反复尝试更新某一个变量,却又一直更新不成功,循环往复,会给CPU带来很大的压力。 - 不能保证代码块的原子性
CAS机制所保证的只是一个变量的原子性操作,而不能保证整个代码块的原子性。比如需要保证3个变量共同进行原子性的更新,就不得不使用Synchronized了。