:::warning 参见: https://github.com/openjdk/jmh/blob/master/jmh-samples/src/main/java/org/openjdk/jmh/samples/JMHSample_15_Asymmetric.java :::
之前介绍的JMH全都是单线程的例子
但真正在生产中, 各种多线程并发的业务数不胜数
同样的代码, 在单线程中的执行效率,与多线程中截然不同, 不是简单的加一个线程速度就翻倍
如果多线程编程中竞态条件会极大的影响我们的执行效率
1. 例子
下面看一个模拟多线程竞争的代码
@State(Scope.Group)@BenchmarkMode(Mode.Throughput)@OutputTimeUnit(TimeUnit.MICROSECONDS)public class Sample_15_Asymmetric {private AtomicInteger counter;@Setuppublic void up() {counter = new AtomicInteger();}@Benchmark@Group("benchmark_thread_competition")@GroupThreads(3)public int inc() {return counter.incrementAndGet();}@Benchmark@Group("benchmark_thread_competition")@GroupThreads(1)public int get() {return counter.get();}}
2. 分析
在这个例子中
inc() 与 get() 是两个方法, 虽然标记了两个 @Benchmark, 但他们是同时执行的
因为我们标记了 @Group(“benchmark_thread_competition”) , 他们在同一个组中
然后
inc() 同时会有3个线程执行
get()同时会有1个线程执行
整个过程中会启动4个线程执行
3. 报表
看看执行结果
Benchmark Mode Cnt Score Error UnitsSample_15_Asymmetric.benchmark_thread_competition thrpt 154.785 ops/usSample_15_Asymmetric.benchmark_thread_competition:get thrpt 127.480 ops/usSample_15_Asymmetric.benchmark_thread_competition:inc thrpt 27.305 ops/us
4. 对照组1
上面的例子是在竞争AtomicInteger对象的时候的执行效率
我们再来看看, 如果没有竞争的话, 执行效率如何
先看看单线程自增操作耗时
@Benchmark@Group("benchmark_inc_no_competition")@GroupThreads(1)public int inc1() {return counter.incrementAndGet();}
单独一个线程, 执行inc()
Benchmark Mode Cnt Score Error UnitsSample_15_Asymmetric.benchmark_inc_no_competition thrpt 164.339 ops/us
发现没, 这个例子中只有一个线程, 但执行效率却远远超过上面三个线程同时inc的效率, 效率大概在6倍左右
多线程反而让执行效率降低了
5. 对照组2
再看看但线程get操作耗时
@Benchmark@Group("benchmark_get_no_competition")public int get1() {// 这个benchmark只有一个线程在执行get操作// 效率直接拉满return counter.get();}
Benchmark Mode Cnt Score Error UnitsSample_15_Asymmetric.benchmark_get_no_competition thrpt 615.008 ops/us
执行效率是原来的5倍左右,
6. 总结
JMH对多线程的支持很完善, 提供了许多工具, 让我们有能力模拟真实的业务场景, 我们要善加利用
