【面试八股】:CAS指令

一、CAS 面试题

1. 说说CAS、CAS有什么问题(ABA)?(美团一面)

Compare And Swap 对比交换(原子指令)

CAS是 CPU指令 操作系统原生 API,JVM对它进行了封装(C++),供我们使用。

通过判断 内存寄存器(预期值) 中的值是否一致,来决定是否执行 写指令,改变内存的值

判断在赋值前是否有 其他线程 改变了 内存 中的值一致就说明没有改变,通过赋值改变内存中的值。不一致就返回,预期值改变 去进行下一次循环


2. CAS如果失败会发生什么?(科大讯飞Java后端)

CAS一般搭配循环使用,循环中每次CAS失败后预期值会被更新为最新的内存值!!!

然后进入循环再次进行CAS操作

二、原子类

利用CAS原子的特性,对读写操作的一体操作,封装成一个个类

它们对基本 数据类型 int double.....进行了封装 ,提供一些作用与 ++ ,+=,这类操作的方法,区别是它们操作是原子的,所以不会出现线程安全问题,我们常用的是 Integer Long 类型。


1. 常用方法:


2. 代码示例:



三、CAS实现自旋锁

1. 伪代码:

通过 CAS 看当前锁是否被某个线程持有.  
 // 如果这个锁已经被别的线程持有, 那么就自旋等待.  
 // 如果这个锁没有被别的线程持有, 那么就把 owner 设为当前尝试加锁的线程.  

public class SpinLock {
 private Thread owner = null;
 public void lock(){
 // 通过 CAS 看当前锁是否被某个线程持有.  
 // 如果这个锁已经被别的线程持有, 那么就⾃旋等待.  
 // 如果这个锁没有被别的线程持有, 那么就把 owner 设为当前尝试加锁的线程.  
 while(!CAS(this.owner, null, Thread.currentThread())){
 }
 }
 public void unlock (){
 this.owner = null;
 }
}

四、ABA问题(详解)

我们已经知道了CAS这条指令的基本原理,就是判断当前内存中的值是否和我们预期的值一致,来判断是否有其他线程已经修改过内存中的值,成功就执行写操作,失败就改变预期值,从而实现原子的特性,这一切看着很合理。


但是它有个缺陷:ABA问题,这个问题就是说,我们在判断是否与预期值一致的时候如果已经有个线程将内存中的 改成别的 又将它改成 A CAS是察觉不到的这就是ABA问题

一般这也不会出大问题,但是有极端情况


举个栗子:

假设你的银行卡内有1000元,现在你往出转账500元ATM机卡了,你狂点两下意外产生两个线程都是要-500元

第一个线程内存值是1000,预期值是1000,判断相等后,执行-500的操作,

第二个线程内存变成500,预期值1000不相等,不执行

上方线程二出现问题,结束,这是完美结局。


假如!!!!情况变了第一个线程执行完,中间的时候有人给你转账500

线程二读内存发现 内存是1000(500+500),预期是1000🆗了直接-500........

这样的结果就是,你卡里有1000转出去500进去500一看余额不是1000了,变成500了,寄了。。。。。


虽然我们说,这个情况太巧合了,正好出来两个线程,正好两个线程 中间 加了 和 扣款 相同数目的钱,可是再小的概率,这件事也一定会出现,我们就提出了针对ABA问题的解决策略


1. 解决策略:

对内存中的值赋予一个 版本号,版本号 只加不减 ,每经历一次操作成功版本号++如果发现接下来的操作中,版本号 高于我们 预期的版本号就不执行操作


拿我们刚刚的例子来说:我们给余额一个版本号 并且初始化为 1 ,经过第一次取钱,版本号变成2

经过别人转给你,变成3,等到第二个线程版本号为2才执行,发现你这里是3,直接不执行

通常会采用一些方法来增加版本号的唯一性,比如使用时间戳、随机数等来初始化版本号


但是时间戳的使用也要谨慎,因为我们的地球公转时间和自转时间不是标准的365倍,所以我们要每四年为一个闰年,这一年会多一天,但是我们为了计算机的时间准度,我们会执行闰秒,也就是手动把时间往回调1秒这样,会每隔一段时间执行闰秒。根据的是国家授时中心的数据,往往这一秒就会导致一些问题,所以时间虽然是正向流逝的,但是也有倒流的情况,用时间戳要谨慎......

                                                                    时间倒流

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值