2013-10-21 23 views
0

我一直在尋找到Java API java.util.concurrent.atomic中, 特別是的AtomicInteger類。Java的原子方法

方法註釋說這些方法是原子的。

getAndIncrement()例如:

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

其中,因爲它是記錄,爲 「以原子遞增一個的電流值」。

究竟是什麼使這種方法原子? 從我所看到的,這完全是「非原子」 - 許多週期參與其執行,並聲明

 int next = current + 1; 

例如下一個可設定的值的執行過程中 由另一個線程。

+0

它是原子的,因爲任何其他線程都會將其視爲原子操作。 – zch

回答

2

原子性是在compareAndSet(current, next)方法中處理的。代碼執行增量操作,並且只有在尚未更改的情況下才設置新值,並且這是以原子方式完成的(或者僞造原子行爲)。如果從那時起它已經被改變,那就需要另一次嘗試。所以它可能不是原子的,但它的行爲就像它。

+0

,所以它在操作上是原子操作的,而不是通過管理它的鎖定 - 從代碼或其他阻止其他訪問的方式可以看出。 thx的答案。 – Roam

1

AtomicInteger使用易失性& CAS(比較和交換)的組合來實現整數計數器的線程安全實現。

閱讀&寫入易失性變量具有與使用同步代碼塊獲取和釋放監視器相同的內存語義。所以JMM保證了volatile字段的可見性。

AtomicInteger類將其value字段存儲在一個volatile變量中,因此它是傳統volatile變量的修飾器,但它在需要CAS的硬件級別支持後提供了用於更新值的獨特非阻塞機制(比較和設置)。在低到中等線程爭用下,與同步阻塞增量操作相比,原子更新提供更高的吞吐量。

以下是AtomicInteger類的getAndIncrement()方法的實現。

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

}您可以看到沒有獲取鎖來增加該值,而是在無限循環內部使用CAS來更新新值。

由於AtomicInteger不需要鎖定,因此它可用於編寫線程爭用低至中等的可伸縮應用程序。

+0

易失性聲明使得該值保存在主內存中,並且不被編譯器以任何其他方式進行緩存或操作,以用於優化或其他目的以用於不同方法。 volatile會相當確定 - 不知道詳細信息 - 「該」mem.location在使用時被「阻塞」,但不保證獨佔訪問以確保原子操作。 – Roam

0

如果你看看沒有循環和CAS會發生什麼,這將清楚這裏的原子是什麼意思。

在沒有同步和比較,並設置(所以無需循環),您的代碼會是這樣的

public final int getAndIncrement() { 

     int current = get(); 
     int next = current + 1; 
     set(next); 
     return current; 

} 

在多線程環境中,可能有兩個線程看到當前值爲0 &試圖將值更新爲1。兩次更新但值增加一個。顯然,沒有同步化,不能保證這不會發生。

所以這裏是compareAndSet的幫助,看看在增加到1之前值是否仍爲零。因此,比較和設置我們說,只有當前值爲零時纔將值設置爲1,否則失敗。考慮上述兩個線程更新值的情況,最多隻有一個線程將成功地將值增加到1,而其他線程將失敗。因此尊重該行動的原子性(全部或全部)。

0

如果您將compareAndSet函數實現追蹤到彙編代碼,您會發現它被轉換爲單個彙編指令(cmpxchg for i486,在sun jdk中的文件linux_i486.s中),這是一條單指令它進行值交換,從而提供所需的原子性而不是鎖定。