2011-01-26 50 views
2

我很驚訝Java的AtomicInteger和AtomicLong類沒有模塊化增量的方法(所以在達到極限值後它的值回到零)。Java的Atomic類的模塊化增量

我想我應該錯過一些明顯的東西。什麼是最好的方法來做到這一點?

例如,我想線程之間共享一個簡單的INT,我想每個線程能夠增加,比方說,國防部10

我可以創建一個使用同步/鎖類,但有沒有更好,更簡單的方法?

回答

4

將​​修飾符或塊添加到您的addModular()方法中有什麼困難?

Atomic類沒有這種功能的原因是它們基於當前CPU提供的specific atomic hardware instructions,模塊化算法無法通過鎖定或其他更復雜且潛在效率低下的算法實現,例如馬特建議的那個。

11

只有當你從中讀取數值時,才能得到10的值?

public class AtomicWrappingCounter { 
    private final AtomicLong counter = new AtomicLong(); 
    private final int max; 

    public AtomicWrappingCounter(int max) { 
    this.max = max; 
    } 

    public int get() { 
    return (int) (counter.get() % max); 
    } 

    public int incrementAndGet() { 
    return (int) (counter.incrementAndGet() % max); 
    } 
} 

顯然,如果你可能會增加此計數器超過Long.MAX_VALUE次,你不能使用這種方法,但9百萬的三次方是有很多次被遞增(約292年在1每納秒的速度! )。

+0

不要這些方法需要同步,ColinD?如果一個線程位於incrementAndGet()中,並且增量已完成,但不是模數,並且不同的線程調用get(),它會返回遞增但未模數的值? – Mark 2016-10-19 21:55:16

+1

@Mark:不。模數對每個線程都是本地的。 'AtomicLong`確保一旦調用`incrementAndGet()`,另一個調用`get()`的線程將看到新的值。兩個線程都自己模擬這個值,每個線程都可以看到預期的最終結果。 – ColinD 2016-10-24 01:53:15

8

我認爲最簡單的方法是建立一個包裹對抗自己將其存儲在一個的AtomicInteger值,像

public class AtomicWrappingCounter { 
    private AtomicInteger value; 
    private final int max; 

    public AtomicWrappingCounter(int start, int max) { 
     this.value = new AtomicInteger(start); 
     this.max = max; 
    } 

    public int get() { 
     return value.get(); 
    } 

    /* Simple modification of AtomicInteger.incrementAndGet() */ 
    public int incrementAndGet() { 
     for (;;) { 
      int current = get(); 
      int next = (current + 1) % max; 
      if (value.compareAndSet(current, next)) 
       return next; 
     } 
    } 
} 

爲什麼不AtomicInteger提供這樣的事情本身?誰知道,但我認爲併發框架作者的意圖是提供一些可用於更好地創建自己的更高級功能的構建塊。

+0

他們只需要在框架中實現`get`和`compareAndSet`。所有其他方法都可以建立在這些方法上。 – finnw 2011-01-26 22:54:09

1

我很驚訝Java的AtomicInteger和AtomicLong類沒有模塊化增量的方法。

當一個標準的類不包括「花裏胡哨的」來支持各種不尋常的用例時,不要感到驚訝。設計師必須在他們所包含的內容和他們不包含的內容的某個地方畫線。趨勢是支持常見的用例和不可能以任何其他方式支持的用例。在這種情況下,這些標準都不適用。