CAS无锁机制原理,面试高频问题之一,其实,日常开发中并不会直接使用CAS无锁机制,都是通过一系列封装好的工具类来使用,
说不定面试官不提问,都不知道有这么个东西存在。
1、能说一下你对CAS的理解吗?
参考回答:
通常我们提到保证多线程安全,会想到三种方式,一是使用Synchronize关键字,但是有个问题就是,使用了Synchronize加锁后的多线程相当于串行,执行效率并不是太高,所以在高并发场景下,使用第二种方式Lock锁,Lock锁要比使用Synchronize关键字在性能上有极大的提高,其实Lock锁底层就是通过AQS+CAS机制实现的;第三种方式就是使用Java并发包下的Atomic「e淘米客」原子操作类,使用了原子类后就不需要使用Synchronize关键字或者是Lock加锁也是线程安全的,原子类的底层就是基于CAS无锁算法实现的。
CAS 比较后再交换。CAS有三个操作数,旧值A,新值B,以及需要读取的内存值V,在更新一个变量时,当且仅当A=V相同时,CAS才会将内存值V修改为B,否则什么都不做。
参考回答有点啰嗦了,提到了CAS的应用场景原子类的使用,但多说点显得有丶东西
2、能说一下CAS的实现原理吗?
参考回答
Java里的CAS是通过调用Unsafe「安sei夫」类的native方法,再由C调用CPU底层命令实现的。
如果问到Unsafe?
Unsafe 这个类是 JDK 提供的一个比较底层的类,是一个不安全的类,官方不建议开发者使用的,为啥呢?①Unsafe在未来可能被移除,也就是高版本jdk可能无法运行;②Unsafe中不少方法中必须提供内存地址和被替换对象的地址,中间会有一些计算问题,一旦出现问题就会导致jvm实例崩溃;③Unsafe中提供的直接访问内存的方法不受jvm管理,需要手动操作,如果疏忽可能会触发内存泄漏;
Unsafe通常用来:「额外补充,了解即可」
- 内存管理:包括分配内存、释放内存
- 操作类、对象、变量:通过获取对象和变量偏移量直接修改数据
- 挂起与恢复:将线程阻塞或者恢复阻塞状态
- CAS:调用 CPU 的 CAS 指令进行比较和交换
- 内存屏障:定义内存屏障,避免指令重排序
如果你想了解加深CAS原理,那么可以敲出一个原子类变量,比如AtomicInteger,直接看一下他的源码,找一下Unsafe是怎么大量应用的。
3、能说一下CAS的优缺点?
缺点
- CPU开销比较大:
在并发量比较高的情况下,如果线程反复尝试更新一个变量,却又一直更新不成功,循环往复,会给CPU带来很大的压力。 - 只能保证一个共享变量的原子操作:
只能是一个变量的原子操作,无法确保整个代码块的原子性,也就是在需要保证2个及以上变量共同进行原子性的更新时,就不得不使用Synchronized了 - ABA问题:
假设有一个变量 A ,经修改后变为B,然后又修改为 A,实际已经修改过了,但 CAS 可能无法感知,造成了不合理的值修改操作。
解决方案是:使用版本号,在变量前面追加上版本号,每次变量更新的时候把版本号加一,那么A-B-A 就会变成1A-2B-3A
*优点
在一般情况下,性能优先于锁的使用。
4、最后补充
从思想上来说,Synchronized属于悲观锁,悲观地认为程序中的并发情况严重,所以严防死守。
CAS属于乐观锁,乐观地认为程序中的并发情况不那么严重,所以让线程不断去尝试更新。
CAS和Synchronized没有绝对的好与坏,关键看使用场景。在并发量非常高的情况下,反而用同步锁更合适一些。
18年专科毕业后,期间一度迷茫,最近我创建了一个公众号用来记录自己的成长。