Ily*_* K. 7 java atomic increment jmh
我对多线程增量的最佳性能进行了调查.我检查了基于同步,AtomicInteger和自定义实现的实现,如AtomicInteger,但使用parkNanos(1),对失败的CAS.
private int customAtomic() {
int ret;
for (;;) {
ret = intValue;
if (unsafe.compareAndSwapInt(this, offsetIntValue, ret, ++ret)) {
break;
}
LockSupport.parkNanos(1);
}
return ret;
}
Run Code Online (Sandbox Code Playgroud)
我基于JMH做了基准:明确执行每个方法,每个方法都消耗CPU(1,2,4,8,16次)并且只消耗CPU.每个基准测试方法在1-17线程上在Intel(R)Xeon(R)CPU E5-1680 v2 @ 3.00GHz,8 Core + 8 HT 64Gb RAM上执行.结果让我感到惊讶:
问题:
我尝试执行此测试几次,并且spike总是发生在不同的数字线程中.另外我在另一台机器上试过这个测试,结果是一样的.也许这是测试中的问题.在StackProfiler中自定义impl的"坏情况"中,我看到:
....[Thread state distributions]....................................................................
50.0% RUNNABLE
49.9% TIMED_WAITING
....[Thread state: RUNNABLE]........................................................................
43.3% 86.6% sun.misc.Unsafe.park
5.8% 11.6% com.jad.generated.IncrementBench_incrementCustomAtomicWithWork_jmhTest.incrementCustomAtomicWithWork_thrpt_jmhStub
0.8% 1.7% org.openjdk.jmh.infra.Blackhole.consumeCPU
0.1% 0.1% com.jad.IncrementBench$Worker.work
0.0% 0.0% java.lang.Thread.currentThread
0.0% 0.0% com.jad.generated.IncrementBench_incrementCustomAtomicWithWork_jmhTest._jmh_tryInit_f_benchmarkparams1_0
0.0% 0.0% org.openjdk.jmh.infra.generated.BenchmarkParams_jmhType_B1.<init>
....[Thread state: TIMED_WAITING]...................................................................
49.9% 100.0% sun.misc.Unsafe.park
Run Code Online (Sandbox Code Playgroud)
在"好的情况下":
....[Thread state distributions]....................................................................
88.2% TIMED_WAITING
11.8% RUNNABLE
....[Thread state: TIMED_WAITING]...................................................................
88.2% 100.0% sun.misc.Unsafe.park
....[Thread state: RUNNABLE]........................................................................
5.6% 47.9% sun.misc.Unsafe.park
3.1% 26.3% org.openjdk.jmh.infra.Blackhole.consumeCPU
2.4% 20.3% com.jad.generated.IncrementBench_incrementCustomAtomicWithWork_jmhTest.incrementCustomAtomicWithWork_thrpt_jmhStub
0.6% 5.5% com.jad.IncrementBench$Worker.work
0.0% 0.0% com.jad.generated.IncrementBench_incrementCustomAtomicWithWork_jmhTest.incrementCustomAtomicWithWork_Throughput
0.0% 0.0% java.lang.Thread.currentThread
0.0% 0.0% org.openjdk.jmh.infra.generated.BenchmarkParams_jmhType_B1.<init>
0.0% 0.0% sun.misc.Unsafe.putObject
0.0% 0.0% org.openjdk.jmh.runner.InfraControlL2.announceWarmdownReady
0.0% 0.0% sun.misc.Unsafe.compareAndSwapInt
Run Code Online (Sandbox Code Playgroud)
链接到结果图.X - 线程计数,Y - thpt,op/microsec
UPD
好的,我知道,据我所知,当我使用parkNanos时,一个线程也可以长时间保持锁定(CAS).CAS失败的线程进入休眠状态,只有一个线程正在工作并递增值.我看到,对于大并发级别,当工作量很小时 - AtomicInteger不是更好的方法.但是如果我们增加workSize,例如level = CASThrpt/threadNum,它应该可以正常工作:对于本地机器我设置了workSize = 300,我的测试结果:
Benchmark (workSize) Mode Cnt Score Error Units
IncrementBench.incrementAtomicWithWork 300 thrpt 3 4.133 ± 0.516 ops/us
IncrementBench.incrementCustomAtomicWithWork 300 thrpt 3 1.883 ± 0.234 ops/us
IncrementBench.lockIntWithWork 300 thrpt 3 3.831 ± 0.501 ops/us
IncrementBench.onlyWithWork 300 thrpt 3 4.339 ± 0.243 ops/us
Run Code Online (Sandbox Code Playgroud)
AtomicInteger - 获胜,锁定 - 第二名,自定义 - 第三名.但是尖峰问题仍然不明确.我忘记了java版本:Java(TM)SE运行时环境(版本1.7.0_79-b15)Java HotSpot(TM)64位服务器VM(版本24.79-b02,混合模式)
在同步的情况下,它往往会与锁粘在一起,这意味着一个线程可以长时间持有锁,而不会让另一个线程公平地获取它。这对于多线程来说非常糟糕,但如果您有一个基准测试,如果只有一个线程运行相对较长的时间,该基准测试会表现得更好,那么这是非常好的。
您需要更改测试,以便在使用多个线程时比仅使用一个线程运行得更好,否则您实际上将测试哪种锁定策略的公平性策略最差。
锁定策略尝试调整锁定的执行方式,这就是它可以改变行为的原因,但它不能很好地完成工作,因为代码一开始就不应该是多线程的。
| 归档时间: |
|
| 查看次数: |
228 次 |
| 最近记录: |