写本文主要是简单记录一下JMH的使用方式。JMH全名是Java Microbenchmark Harness,主要为在jvm上运行的程序进行基准测试的工具。作为一个开发人员,在重构代码,或者确认功能的性能时,可以选中这个工具。
本文场景:代码重构,测试新代码和旧代码的性能区别(QPS)
准备工作
- JMH官方使用文档:http://openjdk.java.net/projects/code-tools/jmh/
- 【推荐】JMH GitHub地址(包含示例代码):https://github.com/openjdk/jmh
- IntelliJ(2020.2.3 社区版)
- Intellij 安装插件 JMH Java Microbenchmark Harness
关键参数介绍
测试程序注解介绍
- BenchmarkMode:基准模式
- 参数:value
- Mode.Throughput:单位时间吞吐量(ops)
- Mode.AverageTime:每次操作的平均时间
- Mode.SampleTime:采样每个操作的时间
- Mode.SingleShotTime:测量一次操作的时间
- Mode.All:把上述的都列出来
- 参数:value
- Warmup:预热。在测试代码运行前运行,主要防止 程序初始化 或 jvm运行一段时间后自动优化代码 产生的影响。
- 参数如下:
- iterations:运行次数,默认:-1
- time:每次运行的时间,默认:-1
- timeUnit:运行时间的单位,默认:秒
- batchSize:批处理大小,每次操作调用几次方法,默认:-1
- 参数如下:
- Measurement:具体测试参数。同 Warmup
- Threads:每个进程中的测试线程,可用于类或者方法上。一般选择为cpu乘以2。如果配置了 Threads.MAX ,代表使用 Runtime.getRuntime().availableProcessors() 个线程。
- Fork:
- 参数如下:
- value参数:多少个进程来测试,如果 fork 数是2的话,则 JMH 会 fork 出两个进程来进行测试
- 参数如下:
- State:状态共享范围。
- 参数如下:
- Scope.Thread:不和其他线程共享
- Scope.Group:相同类型的所有实例将在同一组内的所有线程之间共享。每个线程组将提供自己的状态对象
- Scope.Benchmark:相同类型的所有实例将在所有工作线程之间共享
- 参数如下:
- OutputTimeUnit:默认时间单位
程序执行输出内容介绍
- Result内容介绍(因为测试的是 ops,单位是 秒,下面的结果都是基于 ops/s 来说):
- min:最小值
- avg:平均值
- max:最大值
- stdev:标准差,对于平均值的分散程度(一般来讲越小越接近平均值)
- 最终结果介绍:
- Benchmark:jmh程序名
- Mode:程序中设定的 BenchmarkMode
- Cnt:总执行次数(不包含预热)
- Score:格式是 结果是xxx ± xxx,单位时间内的结果,对本程序来说就是 ops/s
- Error:
- Units:单位
代码部分
程序介绍
- 程序一:通过synchronized关键字实现的生产者消费者程序
程序二:通过ReentrantLock实现的生产者消费者程序,将生产者消费者的队列区分开,减少不必要的争抢
结果理论值
具体程序
<properties>
<!-- 指定 jmh 版本号 -->
<version.jmh-core>1.25.2</version.jmh-core>
</properties>
<dependencies>
<!-- 引入 jmh -->
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>${version.jmh-core}</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>${version.jmh-core}</version>
</dependency>
</dependencies>
```java /*
- 被测试程序 1 */ package com.zhqy.juc.producerAndConsumer.jmh;
import org.slf4j.Logger; import org.slf4j.LoggerFactory;
import java.util.LinkedList;
/**
通过 synchronized notify wait 关键字实现生产者、消费者工具
*- @author wangshuaijing
- @version 1.0.0
@date 2020/11/4 5:08 下午 */ public class SynchronizedVersion {
private static final Logger LOGGER = LoggerFactory.getLogger(SynchronizedVersion.class);
private static final int MAX = 20;
private final LinkedList