原子循環計數器
現實當中很多場景,需要進行輪訓服務,比如輪訓在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