2013-06-05 12 views
7

我正在經歷 java.util.concurrent.atomic.AtomicInteger中的源代碼,以瞭解如何在原子由級提供的原子操作來實現。例如 AtomicInteger.getAndIncrement()法源是如下如何在java.util.concurrent.atomic包中定義的類中實現原子性?

public final int getAndIncrement() { 
    for (;;) { 
     int current = get(); 
     int next = current + 1; 
     if (compareAndSet(current, next)) 
      return current; 
    } 
} 

我不能夠理解爲寫一個循環裏面無限的操作順序的目的。它在Java內存模型(JMM)中有什麼特殊用途?請幫我找一個描述性的理解。提前致謝。

+1

您好像忽略了那個循環中正在調用的方法,並且該方法的結果是打破循環的條件。谷歌「比較和交換」 –

+1

這是一個'goto'的經典用例。在'goto'less語言中,我們使用無限循環。 –

回答

4

我無法理解寫作的目的在無限循環內的 操作序列。

要理解爲什麼它處於無限循環中,我覺得有助於理解compareAndSet的作用以及它如何返回false。

Atomically sets the value to the given updated value if the current 
value == the expected value. 

Parameters: 
    expect - the expected value 
    update - the new value 
Returns: 
    true if successful. False return indicates that the actual value was not 
    equal to the expected value 

所以你讀了Returns消息,問這怎麼可能?

如果兩個線程在接近同一時間調用incrementAndGet,並且它們都進入並看到值current == 1。兩個線程都將創建一個線程本地next == 2並嘗試通過compareAndSet進行設置。只有一個線程會根據記錄獲勝,並且失去的線程必須再次嘗試。

這是CAS的工作原理。如果失敗,則嘗試更改該值,如果成功則再試一次,然後繼續。

現在簡單地聲明該字段爲volatile將不起作用,因爲遞增是而非原子。所以,這樣的事情是不從方案安全我解釋

volatile int count = 0; 

public int incrementAndGet(){ 
    return ++count; //may return the same number more than once. 
} 
+1

非常感謝您的澄清。 –

6

我無法理解在無限for循環中編寫操作序列的目的。

這段代碼的目的是爲了確保volatile領域得到適當更新,恕不一個​​鎖的開銷。除非有大量的線程競相更新這個相同的字段,否則這很可能需要幾次才能完成。

volatile關鍵字提供可見性和存儲器的同步保證但其本身並不保證與多個操作原子操作(測試和設置)。如果您正在測試然後設置volatile字段,那麼如果多個線程同時嘗試執行相同的操作,則會出現競爭條件。在這種情況下,如果多個線程同時嘗試增加AtomicInteger,則可能會錯過其中一個增量。這裏的並行代碼使用自旋循環和compareAndSet基本方法,以確保該volatile int只更新至4(例如),如果它仍然是等於3

  1. T1得到原子int和它0
  2. T2得到原子int和它是0
  3. T1加1,它
  4. T1 原子測試,以確保它是0,這是和賣場1.
  5. t2增加了1
  6. T2 原子測試,以確保它是0,這是,所以它有旋轉,然後再試一次。
  7. T2得到原子int和它是1
  8. T2加1,它
  9. T2 原子測試,以確保它是1,它,並保存2

它是否滿足在Java內存模型(JMM)任何特殊用途。

不,它服務的類和方法定義的目的和使用的JMM和周圍volatile語言定義,以達到其目的。JMM定義了該語言與​​,volatile和其他關鍵字以及多個線程如何與緩存和中央內存進行交互。這主要是關於本地代碼與操作系統和硬件的交互,很少有關於Java代碼的內容。

這是compareAndSet(...)方法,獲得通過調用到Unsafe類其中大部分是本地方法的一些包裝靠近JMM:

public final boolean compareAndSet(int expect, int update) { 
    return unsafe.compareAndSwapInt(this, valueOffset, expect, update); 
} 
+0

根據我對易失性的理解:它解決了可見性的目的,而不使用同步或任何形式的顯式鎖定。因此,volatile可以在沒有同步的情況下使用,以實現讀/寫的一致可視性。那麼,爲什麼要使用這個特殊的for循環進行同步呢?如果您可以更多地解釋循環和同步之間的關係,那將會非常有幫助。感謝您的即時回覆。 –

+1

@VaibhavRaj - 循環與同步無關。它循環直到CAS操作成功。 –

+2

'volatile'是關於能見度; AtomicInteger關於* lock-free atomicity *。沒有重試就無法達到這個目標。無限循環=重試。 –

1

Java的compareAndSet是基於CPU比較並交換(CAS)的說明見http://en.wikipedia.org/wiki/Compare-and-swap它將內存位置的內容與給定值進行比較,只有它們相同時,纔會將該內存位置的內容修改爲給定的新值。

在incrementAndGet的情況下,我們讀取當前值並致電compareAndSet(current, current + 1)。如果返回false,則意味着另一個線程會干擾並改變當前值,這意味着我們的嘗試失敗了,我們需要重複整個循環直到成功。

相關問題