2013-07-17 19 views
3

我正在通過AtomicInteger類中addAndGet方法的Java(Java 6)源代碼。AtomicInteger類中的addAndGet的實現

相應的代碼如下:

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

的compareAndSet方法調用來進行分配本機方法。 主要有兩個問題:

  1. 無限循環如何提供幫助?
  2. 什麼情況下,「if (compareAndSet(current,next))」條件可能返回一個錯誤?在 這種情況下,代碼可能會遇到無限循環。如果是 保證compareAndSet總是會返回一個「true」,那麼我們是否可以完全不用這個檢查呢?

類似的質疑都與decrementAndGetgetAndDecrementgetAndAdd方法爲好。

回答

9

無限循環如何提供幫助?

這意味着:重試,直到它工作。 沒有循環,它可能不會第一次成功(見下文)。

什麼情況下,「if(compareAndSet(current,next))」條件可能返回false?

如果兩個線程試圖同時修改該值,就會發生這種情況。其中之一將首先到達那裏。另一個會失敗。

想象兩個線程(A和B)試圖增加從5至6

A: int current = get(); // current = 5 
B: int current = get(); // current = 5 
B: int next = current + delta; // next = 6 
B: if (compareAndSet(current, next)) // OK 
      return next; 
A: int next = current + delta; // next = 6 
A: if (compareAndSet(current, next)) 
    // fails, because "current" is still 5 
    // and that does not match the value which has been changed to 6 by B 

注意,這個類的整點是避免鎖。相反,你有這種「樂觀的貨幣控制」:假設沒有其他人同時在處理數據,如果結果是錯誤的,則回滾並重試。

在這種情況下,代碼可能會遇到一個無限循環

不是真的。對於每個其他線程來說,它只能做一次失敗的事情。從上面的第二次迭代

線程A:

A: int current = get(); => current now 6 
A: int next = current + delta; => next = 7 
A: if (compareAndSet(current, next)) => now OK 

你可以想象一個線程等待永遠如果其他線程不斷更新的價值,而只有結束。爲了避免這種情況,您需要一些「公平性」(在併發包支持中的其他工具)的定義。