一、CAS了解多少?
CAS叫做CompareAndSwap,⽐较并交换,主要是通过处理器的指令来保证操作的原⼦性的。
CAS 指令包含 3 个参数:共享变量的内存地址 A、预期的值 B 和共享变量的新值C。
只有当内存中地址 A 处的值等于 B 时,才能将内存中地址 A 处的值更新为新值C。作为一条 CPU 指令,CAS 指令本身是能够保证原子性的 。
二、CAS 有什么问题?如何解决?
CAS的经典三大问题:
ABA 问题
并发环境下,假设初始条件是A,去修改数据时,发现是A就会执行修改。但是看到的虽然是A,中间可能发生了A变B,B又变回A的情况。此时A已经非彼A,数据即使成功修改,也可能有问题。
怎么解决ABA问题?
加版本号
每次修改变量,都在这个变量的版本号上加1,这样,刚刚A->B->A,虽然A的值没变,但是它的版本号已经变了,再判断版本号就会发现此时的A已经被改过了。参考乐观锁的版本号,这种做法可以给数据带上了一种实效性的检验。
Java提供了AtomicStampReference类,它的compareAndSet方法首先检查当前的对象引用值是否等于预期引用,并且当前印戳(Stamp)标志是否等于预期标志,如果全部相等,则以原子方式将引用值和印戳标志的值更新为给定的更新值。
循环性能开销
自旋CAS,如果一直循环执行,一直不成功,会给CPU带来非常大的执行开销。
怎么解决循环性能开销问题?
在Java中,很多使用自旋CAS的地方,会有一个自旋次数的限制,超过一定次数,就停止自旋。
只能保证一个变量的原子操作
CAS 保证的是对一个变量执行操作的原子性,如果对多个变量操作时,CAS 目前无法直接保证操作的原子性的。
怎么解决只能保证一个变量的原子操作问题?
可以考虑改用锁来保证操作的原子性
可以考虑合并多个变量,将多个变量封装成一个对象,通过AtomicReference来保证原子性。