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