声明:不足之处,请指正
一、CAS与ABA
- CAS
CAS
就是"compare and set",意味比对旧值,如果旧值符合预期则更新为新值 - ABA
ABA
不能说是CAS
的缺陷,应该说CAS
在大部分的应用场景并不严谨,然后才会导致ABA
问题。目前大部分CAS
的应用场景都是为了判别一个变量是否被其他线程动过,如果变量的值符合预期,则判断变量没有被动过,故可以进行新值的更新。但是,变量的值符合预期并不能真正说明变量没有被变更过。也许,预期的A值是其他线程经过一系列操作之后的才出现的。所以说,如果你可以保证变量的值符合预期,我就可以给其更新新的值,那么ABA
并不是问题,比如该值永远都不会重复,那么也不存在ABA
问题了。如果不能保证这一点,就需要去解决ABA
问题。
二、ABA的解决方法
- ABA的解决思路
既然无法确定即使旧值符合预期,变量是否依然被变更过,那么就给这个变量添加一个版本,版本值一定不能重复使用,不然又会出现ABA
问题。如果版本变动过,那么说明该值是不可信的。 - 解决ABA的类
AtomicStampedReference
//0是版本号
AtomicStampedReference atomicStampedRef = new AtomicStampedReference(100, 0);
三、附上经典的ABA问题
现有一个用单向链表实现的堆栈,栈顶为A,这时线程T1已经知道A.next为B,然后希望用CAS将栈顶替换为B:
head.compareAndSet(A,B);
在T1执行上面这条指令之前,线程T2介入,将A、B出栈,再pushD、C、A,此时堆栈结构如下图,而对象B此时处于游离状态:
此时轮到线程T1执行CAS操作,检测发现栈顶仍为A,所以CAS成功,栈顶变为B,但实际上B.next为null,所以此时的情况变为:
其中堆栈中只有B一个元素,C和D组成的链表不再存在于堆栈中,平白无故就把C、D丢掉了。
参考文档:
[1] 用AtomicStampedReference解决ABA问题
网友评论