感谢同事[孙棋]的投稿
现实当中很多场景,需要进行轮训服务,比如轮训在10个日志文件当中写日志,在10台机器上轮训的去调用以实现负载均衡,常规的做法,如tomcat的Poller线程轮训选择,就采用
1 |
Math.abs(pollerRotater.incrementAndGet()) % pollers.length |
此地需要取原子自增的绝对值模以poller线程数,那是否有更好的实现呢?
01 |
public class CycleAtomicInteger {
|
02 |
private final static long PARK_TIME = 1000L * 1000 ;
|
03 |
04 |
private AtomicInteger counter = new AtomicInteger( 0 );
|
05 |
06 |
private int range;
|
07 |
08 |
public CycleAtomicInteger( int range) {
|
09 |
if (range < 2 )
|
10 |
throw new IllegalArgumentException();
|
11 |
this .range = range;
|
12 |
} |
13 |
14 |
/** |
15 |
* 获取下个原子值
|
16 |
*
|
17 |
* @return
|
18 |
*/
|
19 |
public int next() {
|
20 |
for (;;) {
|
21 |
int c = counter.get();
|
22 |
int next = (c + 1 ) % range;
|
23 |
if (counter.compareAndSet(c, next)) {
|
24 |
return c;
|
25 |
} else {
|
26 |
LockSupport.parkNanos(PARK_TIME);
|
27 |
}
|
28 |
}
|
29 |
} |
30 |
31 |
} |
这样就可以快速的实现rr的效果,同时也避免了abs的过程,至于LockSupport.parkNanos(PARK_TIME);加了这个后,4个线程执行2亿次的计算,我本机从原来的16s减少到4s,至于为什么要加这个,可参见更快的AtomicInteger
当然,这样设计会存在cas的aba问题,但对当前的case需求,其实是满足的,也不存在问题
时间: 2024-08-04 01:01:58