CAS原理分析,解决银行转账ABA难题
时间:2021-10-11 13:44:12
手机看文章
扫描二维码
随时随地手机看文章
[导读]来源:https://ddnd.cn/2019/03/13/java-cas/ 什么是CASCAS即CompareAndSwap的缩写,翻译成中文就是比较并交换,其作用是让CPU比较内存中某个值是否和预期的值相同,如果相同则将这个值更新为新值,不相同则不做更新,也就是CAS是原子...
什么是CAS
Unsafe源码分析
Unsafe有很多个CAS操作的相关方法,这里举例几个
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);
-
将对象引用、值在对象中的偏移量、期望的值和欲更新的新值传递给Unsafe.cpp
-
如果值更新成功则返回true给开发者,没有更新则返回false
-
接受从Unsafe传递过来的对象引用、偏移量、期望的值和欲更新的新值,根据对象引用和偏移量计算出值的地址,然后将值的地址、期望的值、欲更新的新值传递给CPU
-
如果值更新成功则返回true给Unsafe.java,没有更新则返回false
-
接受从Unsafe.cpp传递过来的地址、期望的值和欲更新的新值,执行指令cmpxchg,比较地址中的值是否和期望的值一样,一样则将值更新为新的值,不一样则不做任何操作
-
将操作结果返回给Unsafe.cpp
CAS的缺点
ABA问题
-
线程1,期望值为A,欲更新的值为B
-
线程2,期望值为A,欲更新的值为B
小明在提款机,提取了50元,因为提款机问题,有两个线程,同时把余额从100变为50
线程1(提款机):获取当前值100,期望更新为50,
线程2(提款机):获取当前值100,期望更新为50,
线程1成功执行,线程2某种原因block了,这时,某人给小明汇款50
线程3(默认):获取当前值50,期望更新为100,
这时候线程3成功执行,余额变为100,
线程2从Block中恢复,获取到的也是100,compare之后,继续更新余额为50!!!
此时可以看到,实际余额应该为100(100-50 50),但是实际上变为了50(100-50 50-50)这就是ABA问题带来的成功提交。
循环时间长开销大
这种循环也称为自旋
只能保证一个共享变量的原子操作
CAS的应用
-
乐观锁总是假设最好的情况,每次去操作数据都认为不会被别的线程修改数据,所以在每次操作数据的时候都不会给数据加锁,即在线程对数据进行操作的时候,别的线程不会阻塞仍然可以对数据进行操作,只有在需要更新数据的时候才会去判断数据是否被别的线程修改过,如果数据被修改过则会拒绝操作并且返回错误信息给用户。
-
悲观锁总是假设最坏的情况,每次去操作数据时候都认为会被的线程修改数据,所以在每次操作数据的时候都会给数据加锁,让别的线程无法操作这个数据,别的线程会一直阻塞直到获取到这个数据的锁。这样的话就会影响效率,比如当有个线程发生一个很耗时的操作的时候,别的线程只是想获取这个数据的值而已都要等待很久。