更快的AtomicInteger

之前看了java8longadder实现,最近又看到一篇文章介绍longadder的,http://ifeve.com/atomiclong-and-longadder/

其实现思路也是分段,最后需要get的时候进行sum计算。其核心思路就是减少并发,但之前老的Atomic,难道就没有提升的空间了吗?昨晚进行了一次测试

 

  /**

     * Atomically increments by one the current value.

     *

     * @return the updated value

     */

    publicfinalint incrementAndGet() {

        for (;;) {

            int current = get();

            int next = current + 1;

            if (compareAndSet(current, next))

                return next;

        }

    }

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

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

 

publicclass AtomicBetter {

       AtomicInteger ai = new AtomicInteger();

      

       publicint incrementAndGet() {

              for (;;) {

                     int current = ai.get();

                     int next = current + 1;

                     if (compareAndSet(current, next))

                            return next;

              }

       }

       /**

       * 如果cas失败,线程park

       * @param current

       * @param next

       * @return

       */

       privateboolean compareAndSet(int current, int next) {

              if (ai.compareAndSet(current, next)) {

                     returntrue;

              } else {

                     LockSupport.parkNanos(1);

                     returnfalse;

              }

       }

 

}

很简单,当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多少合适呢?那就只有人肉测试了

 

park

time ms

context-switches

cycles

AtomicInteger

14232

35,870

87,967,770,955

1ns

5195

19,779

36,187,480,878

10ns

5050

20,223

34,839,351,263

100ns

5238

20,724

37,250,431,417

125ns

4536

47,479

26,149,046,788

140ns

4008

100,022

18,342,728,517

150ns

3864

110,720

16,146,816,453

200ns

3561

125,694

11,793,941,243

300ns

3456

127,072

10,200,338,988

500ns

3410

132,163

9,545,542,340

1us

3376

134,463

9,125,973,290

5us

3383

122,795

9,009,226,315

10us

3367

113,930

8,905,263,507

100us

3391

50,925

8,359,532,733

500us

3456

17,225

8,096,303,146

1ms

3486

10,982

7,993,812,198

10ms

3456

2,600

7,845,610,195

100ms

3555

1,020

7,804,575,756

500ms

3854

822

7,814,209,077

 

 

 

 

 

 

 

 

 

 

 

 

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

两个问题:

<!--[if !supportLists]-->1、<!--[endif]-->cas失败对线程park的副作用是什么

<!--[if !supportLists]-->2、<!--[endif]-->如果park的时间继续加大,那会是这么样的结果呢

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值