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