CAS中的ABA問題

補檔CAS中的ABA問題。java

要特別注意,常見的ABA問題有兩種,要求能分別舉例解釋。node

CAS的使用可參考:git

1 定義

1.1 基本的ABA問題

在CAS算法中,須要取出內存中某時刻的數據(由用戶完成),在下一時刻比較並替換(由CPU完成,該操做是原子的)。這個時間差中,會致使數據的變化。程序員

假設以下事件序列:github

  1. 線程 1 從內存位置V中取出A。
  2. 線程 2 從位置V中取出A。
  3. 線程 2 進行了一些操做,將B寫入位置V。
  4. 線程 2 將A再次寫入位置V。
  5. 線程 1 進行CAS操做,發現位置V中仍然是A,操做成功。

儘管線程 1 的CAS操做成功,但不表明這個過程沒有問題——對於線程 1 ,線程 2 的修改已經丟失算法

1.2 與內存模型相關的ABA問題

在沒有垃圾回收機制的內存模型中(如C++),程序員可隨意釋放內存。併發

假設以下事件序列:spa

  1. 線程 1 從內存位置V中取出A,A指向內存位置W。
  2. 線程 2 從位置V中取出A。
  3. 線程 2 進行了一些操做,釋放了A指向的內存。
  4. 線程 2 從新申請內存,並剛好申請了內存位置W,將位置W存入C的內容。
  5. 線程 2 將內存位置W寫入位置V。
  6. 線程 1 進行CAS操做,發現位置V中仍然是A指向的即內存位置W,操做成功

這裏比問題 1.1 的後果更嚴重,實際內容已經被修改了,但_線程 1 沒法感知到線程 2 的修改_。線程

更甚,若是線程 2 只釋放了A指向的內存,而線程 1 在 CAS以前還要訪問A中的內容,那麼線程 1 將訪問到一個野指針指針

2 舉例

2.1 基本的ABA問題舉例

若是位置V存儲的是鏈表的頭結點,那麼發生ABA問題的鏈表中,原頭結點是node1,線程 2 操做頭結點變化了兩次,極可能是先修改頭結點爲node2,再將node1(在C++中,也但是從新分配的節點node3,但剛好其指針等於已經釋放掉的node1)插入表頭成爲新的頭結點。

對於線程 1 ,頭結點仍舊爲 node1(或者說頭結點的值,由於在C++中,雖然地址相同,但其內容可能變爲了node3),CAS操做成功,但頭結點以後的子鏈表的狀態已不可預知。

腦補示意圖。。

2.2 與內存模型相關的ABA問題舉例

問題定義已闡述清楚。

3 解決

Java的垃圾回收機制已經幫咱們解決了問題 1.2;至於問題 1.1,加入版本號便可解決。

3.1 AtomicStampedReference

除了對象值,AtomicStampedReference內部還維護了一個「狀態戳」。狀態戳可類比爲時間戳,是一個整數值,每一次修改對象值的同時,也要修改狀態戳,從而區分相同對象值的不一樣狀態。當AtomicStampedReference設置對象值時,對象值以及狀態戳都必須知足指望值,寫入纔會成功。

AtomicStampedReference的幾個API在AtomicReference的基礎上新增了有關時間戳的信息:

//比較設置 參數依次爲:指望值 寫入新值 指望時間戳 新時間戳
public boolean compareAndSet(V expectedReference, V newReference, int expectedStamp, int newStamp) //得到當前對象引用 public V getReference() //得到當前時間戳 public int getStamp() //設置當前對象引用和時間戳 public void set(V newReference, int newStamp) 複製代碼

3.2 AtomicMarkableReference

AtomicMarkableReference和AtomicStampedReference功能類似,但AtomicMarkableReference描述更加簡單的是與否的關係。它的定義就是將狀態戳簡化爲true|false。以下:

public final static AtomicMarkableReference<String> ATOMIC_MARKABLE_REFERENCE 
    = new AtomicMarkableReference<>("abc" , false); 
複製代碼

操做時:

ATOMIC_MARKABLE_REFERENCE.compareAndSet("abc", "abc2", false, true);
複製代碼

本文連接:CAS中的ABA問題
做者:猴子007
出處:monkeysayhi.github.io
本文基於 知識共享署名-相同方式共享 4.0 國際許可協議發佈,歡迎轉載,演繹或用於商業目的,可是必須保留本文的署名及連接。

相關文章
相關標籤/搜索