更快的AtomicInteger

感谢同事【空蒙】的投稿

之前看了java8的longadder实现,最近又看到一篇文章介绍longadder实现的。其实现思路也是分段,最后需要get的时候,再进行sum计算。其核心思路就是减少并发,但之前老的Atomic,难道就没有提升的空间了吗?昨晚进行了一次测试。测试代码如下:


01/**
02* Atomically increments by one the current value.
03*
04*@return the updated value
05*/
06 public final int incrementAndGet() {
07 
08   for(;;) {
09 
10    int current = get();
11 
12     int next = current + 1;
13 
14     if(compareAndSet(current, next))
15 
16     return next;
17 
18    }
19}

以incrementAndGet为例,在非常高的并发下,compareAndSet会很大概率失败,因此导致了此处cpu不断的自旋,对cpu资源的浪费

既然知道此地是高并发的瓶颈,有什么办法呢?


01 public class AtomicBetter {
02 
03       AtomicInteger ai=new AtomicInteger();
04 
05       public int incrementAndGet() {
06 
07              for(;;) {
08 
09                     int current =ai.get();
10 
11                     int next = current + 1;
12 
13                     if(compareAndSet(current, next))
14 
15                            return next;
16 
17               }
18 
19        }
20 
21       /**
22 
23        *如果cas失败,线程park
24 
25        *@paramcurrent
26 
27        *@paramnext
28 
29        *@return
30 
31        */
32 
33       private boolean compareAndSet(intcurrent,intnext) {
34 
35              if(ai.compareAndSet(current, next)) {
36 
37                     return true;
38 
39               }else{
40 
41                      LockSupport.parkNanos(1);
42 
43                     return false;
44 
45               }
46 
47        }
48 
49}

很简单,当cas失败后,对线程park,减少多线程竞争导致的频繁cas失败,更进一步的导致cpu自旋,浪费cpu的运算能力。在4核虚拟机,Intel(R) Xeon(R) CPU E5-2630 0 @ 2.30GHz  linux 2.6.32,(注意,老版本的内核,不支持高的精度ns级) 进行测试,同样都起4个线程,每个线程里面对AtomicInteger进行5kw次的incrementAndGet。原生的AtomicInteger,耗时14232ms,进行了35870次上下文切换,总共87967770955次时钟周期。那prak 1ns下呢,耗时5195ms,进行了19779次上下文切换,总共36187480878次时钟周期,明显性能上比原生的AtomicInteger更好,那这个park多少合适呢?那就只有人肉测试了

parktime(ms)context-switchescycles
AtomicInteger1423235,87087,967,770,955
1ns519519,77936,187,480,878
10ns505020,22334,839,351,263
100ns523820,72437,250,431,417
125ns453647,47926,149,046,788
140ns4008100,02218,342,728,517
150ns3864110,72016,146,816,453
200ns3561125,69411,793,941,243
300ns3456127,07210,200,338,988
500ns3410132,1639,545,542,340
1us3376134,4639,125,973,290
5us3383122,7959,009,226,315
10us3367113,9308,905,263,507
100us339150,9258,359,532,733
500us345617,2258,096,303,146
1ms348610,9827,993,812,198
10ms34562,6007,845,610,195
100ms35551,0207,804,575,756
500ms38548227,814,209,077

 

alt

 

alt

 

alt

本机环境下,park 1ms下,相对耗时,cs次数来说是最好的。因此这种优化要达到最佳效果,还要看cpu的情况而定,不是一概而定的

两个问题:

1、cas失败对线程park的副作用是什么。

2、如果park的时间继续加大,那会是这么样的结果呢。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值