java atomicinteger_更快的AtomicInteger

文章探讨了在高并发场景下,AtomicInteger的incrementAndGet方法可能导致的CPU自旋问题,并提出了一种优化策略:当CAS失败时,线程park短暂时间以减少竞争。通过在不同park时间下的性能测试,发现park 1ms在某些环境下能有效降低上下文切换次数和提高性能。但优化效果依赖于具体CPU情况,park时间的选择需要根据实际环境调整。
摘要由CSDN通过智能技术生成

感谢同事【空蒙】的投稿

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

/**

* Atomically increments by one the current value.

*

*@return the updated value

*/

public final int incrementAndGet() {

for(;;) {

int current = get();

int next = current + 1;

if(compareAndSet(current, next))

return next;

}

}

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

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

public class AtomicBetter {

AtomicInteger ai=new AtomicInteger();

public int incrementAndGet() {

for(;;) {

int current =ai.get();

int next = current + 1;

if(compareAndSet(current, next))

return next;

}

}

/**

*如果cas失败,线程park

*@paramcurrent

*@paramnext

*@return

*/

private boolean compareAndSet(intcurrent,intnext) {

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

return true;

}else{

LockSupport.parkNanos(1);

return false;

}

}

}

很简单,当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

7d6ada334b8b58a2d8a4c5c5ea94178b.png

b6c6b2b2f614bbc84c3e1eca2027118d.png

e451ddad8040b1575f95fe31792327f5.png

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

两个问题:

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

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

d0c1501a6d8bb921cf36400dc89de69f.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值