CAS ABA问题

java.util.concurrent包的最底层基础CAS技术,原理很简单。java

CAS有3个操做数,内存值V,旧的预期值A,要修改的新值B。当且仅当预期值A和内存值V相同时,将内存值V修改成B,不然什么都不作。并发

引起ABA问题:若是变量V初次读取的时候是A,而且在准备赋值的时候检查到它仍然是A,那能说明它的值没有被其余线程修改过了吗?若是在这段期间它的值曾经被改为了B,而后又改回A,那CAS操做就会误认为它历来没有被修改过。spa

举例:线程

线程1准备用CAS将变量的值由A替换为B,在此以前,线程2将变量的值由A替换为C,又由C替换为A,而后线程1执行CAS时发现变量的值仍然为A,因此CAS成功。但实际上这时的现场已经和最初不一样了,尽管CAS成功,但可能存在潜藏的问题,例以下面的例子:对象

 

现有一个用单向链表实现的堆栈,栈顶为A,这时线程T1已经知道A.next为B,而后但愿用CAS将栈顶替换为B:blog

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丢掉了。原理

解决办法:针对这种状况,java并发包中提供了一个带有标记的原子引用类"AtomicStampedReference"(版本戳),它能够经过控制变量值的版原本保证CAS的正确性。

相关文章
相关标签/搜索