目录
面试中比较容易考到CAS问题 并且一旦考到,一定会涉及ABA问题
CAS(M,A,B)
M内存 A、B两个寄存器
如果M中的值和A相同,则交换M和B的值(交换的目的是将B赋值给M,我们不关心寄存器中的值)
如果M中的值和A不相同,则无事发生,同时整个操作返回false
//伪代码
boolean CAS(address,expectValue,swapValue){
if(&address==expectValue){
&address=swapValue;
return true;
}
return false;
}
CAS操作主要有三个参数:要更新的内存位置、期望的值和新值。CAS操作的执行过程如下:
①首先,获取要更新的内存位置的值,记为var。
②然后,将期望值expected与var进行比较,如果两者相等,则将内存位置的值var更新为新值new。
③如果两者不相等,则说明有其他线程修改了内存位置的值var,此时CAS操作失败,需要重新尝试。加锁是通过阻塞的方式,避免穿插
CAS是通过重试的方式,避免穿插
CAS本质是一个cpu指令,是单个指令(原子的),所以,可以用CAS完成一些操作,进一步代替加锁操作
基于CAS实现线程安全的方式,也称为”无锁编程“
优点:保证线程安全,同时避免阻塞(效率)
缺点:代码更复杂,不好理解;只能适合一些特定场景,不如加锁更普遍
ABA问题
有第三个线程穿插,使得值A->B->A
针对第一个线程,值看起来还是A,但是已经被穿插执行了
大部分情况下ABA不会出现bug(值又被改回去了),但也有一些极端情况
如何避免ABA问题出现?
让判定的数值按照一个方向增长(只是增加或者只是减少)
如果有增有减,可以引入一个额外的变量——版本号,约定每次修改时,让版本号自增,使用CAS判定时,看版本号是否变化,若无变化,则是没有线程穿插执行