cas这么好用,那么有没有什么问题呢?还真有
ABA问题
CAS须要在操做值的时候检查下值有没有发生变化,若是没有发生变化则更新,可是若是一个值原来是A,变成了B,又变成了A,那么使用CAS进行检查时会发现它的值没有发生变化,可是实际上却变化了。这就是CAS的ABA问题。 常见的解决思路是使用版本号。在变量前面追加上版本号,每次变量更新的时候把版本号加一,那么A-B-A 就会变成1A-2B-3A。 目前在JDK的atomic包里提供了一个类AtomicStampedReference来解决ABA问题。这个类的compareAndSet方法做用是首先检查当前引用是否等于预期引用,而且当前标志是否等于预期标志,若是所有相等,则以原子方式将该引用和该标志的值设置为给定的更新值。
循环时间长开销大
上面咱们说过若是CAS不成功,则会原地循环(自旋操做),若是长时间自旋会给CPU带来很是大的执行开销。并发量比较大的状况下,CAS成功几率可能比较低,可能会重试不少次才会成功。
解决ABA最简单的方案就是给值加一个修改版本号,每次值变化,都会修改它版本号,CAS操做时都对比此版本号
JAVA中ABA中解决方案(AtomicStampedReference)
AtomicStampedReference主要维护包含一个对象引用以及一个能够自动更新的整数"stamp"的pair对象来解决ABA问题。
AtomicStampedRerence正是这么作的,他内部不只维护了对象的值,还维护了一个时间戳(咱们这里把他称为时间戳,实际上它可使用任何一个整形来表示状态值),当AtomicStampedRerence对应的数值被修改时,除了更新数据自己外,还必需要更新时间戳。当AtomicStampedRerence设置对象值时,对象值及时间戳都必须知足指望值,写入才会成功。所以,即便对象值被反复读写,写回原值,只要时间戳发生变量,就能防止不恰当的写入