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的正確性。