CAS(Compare And Swap)
什么是原子操作?如何实现原子操作?
答:要么都完成,要么都不完成--- 他们是不可以分割的,就是原子操作
比如:synchronized 包裹的内容就是原子操作
但是,synchronized 就是抢夺锁,这是一个很重的操作.所以就引进CAS(Compare and swap)
现代CPU 将 Compare And Swap
打包成一个原子指令
CAS的原理
比如: 有A ,B,C 三个线程执行 count++
的操作
- A线程:记录count 初始值, 完成
++
操作后, 执行 写入操作的时候: 先Compare( 比较初始值是否变化)-->没有变化
则(Swap:替换). A线程结束 - B 线程: 完成
++
操作后, 执行 写入操作的时候: 先Compare( 比较初始值是否变化)-->变化
则以变化后的值为初始值. 继续循环 - C 等线程也是
B这样的循环
.直到结束.
引申的话题
`CAS` 是乐观锁: 每次执行都是进行,直到最后才决定swap.
synchronized 是悲观锁: 总有"刁民想害朕",只有真的获取锁资源才会执行.
CAS的优势
synchronized 涉及上下文切换,资源消耗大. 所以CAS 乐观锁的性能更好
CAS的不足
问题1:ABA 问题
假设:线程1 和线程2
线程1的操作: A---设置-->B
, 最后做compare and swap的时候:
if 初始值A ,则设置成B
线程2的操作: A--->C--->A
并且线程2的更早执行.
如此,造成了明明修改了.但是线程1不知道
解决ABA 的思路: 在变量前面追加版本号,每次变量更新版本就会更新. 当swap的时候,同时比较值和版本号
比如:AtomicMarkableReference,AtomicStampedReference
AtomicMarkableReference
: 关心有没有动过(bool)
AtomicStampedReference
:关系修改的次数(count)
问题2:开销 问题
因为自旋的原因,对CPU 的执行有大开销
问题3: 只能保证一个共享变量的原子操作
当多个字段改变的原子操作的时候有问题
解决一个共享变量的原子操作: 将多个共享变量合并成一个共享变量进行CAS
比如: AtomicReference
, 可以把多个变量组合在一个对象里面