閱讀458 返回首頁    go 阿裏雲 go 技術社區[雲棲]


原子循環計數器

現實當中很多場景,需要進行輪訓服務,比如輪訓在10個日誌文件當中寫日誌,在10台機器上輪訓的去調用以實現負載均衡,常規的做法,如tomcat的Poller線程輪訓選擇,就采用

Math.abs(pollerRotater.incrementAndGet()) % pollers.length

此地需要取原子自增的絕對值模以poller線程數,那是否有更好的實現呢?

public class CycleAtomicInteger {
private final static long PARK_TIME = 1000L * 1000;

private AtomicInteger counter = new AtomicInteger(0);

private int range;

public CycleAtomicInteger(int range) {
    if (range < 2)
        throw new IllegalArgumentException();
    this.range = range;
}

/**
 * 獲取下個原子值
 *
 * @return
 */
public int next() {
    for (;;) {
        int c = counter.get();
        int next = (c + 1) % range;
        if (counter.compareAndSet(c, next)) {
            return c;
        } else {
            LockSupport.parkNanos(PARK_TIME);
        }
    }
}

}

這樣就可以快速的實現rr的效果,同時也避免了abs的過程,至於LockSupport.parkNanos(PARK_TIME);加了這個後,4個線程執行2億次的計算,我本機從原來的16s減少到4s,至於為什麼要加這個,可參見更快的AtomicInteger

當然,這樣設計會存在cas的aba問題,但對當前的case需求,其實是滿足的,也不存在問題

最後更新:2017-05-23 18:02:22

  上一篇:go  並發編程 Promise, Future 和 Callback
  下一篇:go  Java 正則表達式