别再写 main 方法测试了,太 Low!这才是专业 Java 测试方法!
上一篇:还在用策略模式解决 if-else?Map+函数式接口方法才是YYDS! 
"If you cannot measure it, you cannot improve it".

JMH的使用场景:
1. 测试项目构建
第一种是使用命令行构建,在指定目录下执行以下命令:
$ mvn archetype:generate \-DinteractiveMode=false \-DarchetypeGroupId=org.openjdk.jmh \-DarchetypeArtifactId=jmh-java-benchmark-archetype \-DgroupId=org.sample \-DartifactId=test \-Dversion=1.0
对应目录下会出现一个test项目,打开项目后我们会看到这样的项目结构。

org.openjdk.jmh jmh-core ${jmh.version} org.openjdk.jmh jmh-generator-annprocess ${jmh.version} provided 
2. 编写性能测试
/*** @author Richard_yyf* @version 1.0 2019/8/27*/@State(Scope.Benchmark)@OutputTimeUnit(TimeUnit.SECONDS)@Threads(Threads.MAX)public class LinkedListIterationBenchMark {private static final int SIZE = 10000;private Listlist = new LinkedList<>(); @Setuppublic void setUp() {for (int i = 0; i < SIZE; i++) {list.add(String.valueOf(i));}}@Benchmark@BenchmarkMode(Mode.Throughput)public void forIndexIterate() {for (int i = 0; i < list.size(); i++) {list.get(i);System.out.print("");}}@Benchmark@BenchmarkMode(Mode.Throughput)public void forEachIterate() {for (String s : list) {System.out.print("");}}}
3. 执行测试
生成jar文件的形式主要是针对一些比较大的测试,可能对机器性能或者真实环境模拟有一些需求,需要将测试方法写好了放在linux环境执行。具体命令如下
$ mvn clean install$ java -jar target/benchmarks.jar
我们日常中遇到的一般是一些小测试,比如我上面写的例子,直接在IDE中跑就好了。启动方式如下:
public static void main(String[] args) throws RunnerException {Options opt = new OptionsBuilder().include(LinkedListIterationBenchMark.class.getSimpleName()).forks(1).warmupIterations(2).measurementIterations(2).output("E:/Benchmark.log").build();new Runner(opt).run();}
输出结果如下
最后的结果:
Benchmark Mode Cnt Score Error UnitsLinkedListIterationBenchMark.forEachIterate thrpt 2 1192.380 ops/sLinkedListIterationBenchMark.forIndexIterate thrpt 2 206.866 ops/s
# Detecting actual CPU count: 12 detected# JMH version: 1.21# VM version: JDK 1.8.0_131, Java HotSpot(TM) 64-Bit Server VM, 25.131-b11# VM invoker: C:\Program Files\Java\jdk1.8.0_131\jre\bin\java.exe# VM options: -javaagent:D:\Program Files\JetBrains\IntelliJ IDEA 2018.2.2\lib\idea_rt.jar=65175:D:\Program Files\JetBrains\IntelliJ IDEA 2018.2.2\bin -Dfile.encoding=UTF-8# Warmup: 2 iterations, 10 s each# Measurement: 2 iterations, 10 s each# Timeout: 10 min per iteration# Threads: 12 threads, will synchronize iterations# Benchmark mode: Throughput, ops/time# Benchmark: org.sample.jmh.LinkedListIterationBenchMark.forEachIterate# Run progress: 0.00% complete, ETA 00:01:20# Fork: 1 of 1# Warmup Iteration 1: 1189.267 ops/s# Warmup Iteration 2: 1197.321 ops/sIteration 1: 1193.062 ops/sIteration 2: 1191.698 ops/sResult "org.sample.jmh.LinkedListIterationBenchMark.forEachIterate":1192.380 ops/s# JMH version: 1.21# VM version: JDK 1.8.0_131, Java HotSpot(TM) 64-Bit Server VM, 25.131-b11# VM invoker: C:\Program Files\Java\jdk1.8.0_131\jre\bin\java.exe# VM options: -javaagent:D:\Program Files\JetBrains\IntelliJ IDEA 2018.2.2\lib\idea_rt.jar=65175:D:\Program Files\JetBrains\IntelliJ IDEA 2018.2.2\bin -Dfile.encoding=UTF-8# Warmup: 2 iterations, 10 s each# Measurement: 2 iterations, 10 s each# Timeout: 10 min per iteration# Threads: 12 threads, will synchronize iterations# Benchmark mode: Throughput, ops/time# Benchmark: org.sample.jmh.LinkedListIterationBenchMark.forIndexIterate# Run progress: 50.00% complete, ETA 00:00:40# Fork: 1 of 1# Warmup Iteration 1: 205.676 ops/s# Warmup Iteration 2: 206.512 ops/sIteration 1: 206.542 ops/sIteration 2: 207.189 ops/sResult "org.sample.jmh.LinkedListIterationBenchMark.forIndexIterate":206.866 ops/s# Run complete. Total time: 00:01:21REMEMBER: The numbers below are just data. To gain reusable insights, you need to follow up onwhy the numbers are the way they are. Use profilers (see -prof, -lprof), design factorialexperiments, perform baseline and negative tests that provide experimental control, make surethe benchmarking environment is safe on JVM/OS/HW level, ask for reviews from the domain experts.Do not assume the numbers tell you what you want them to tell.Benchmark Mode Cnt Score Error UnitsLinkedListIterationBenchMark.forEachIterate thrpt 2 1192.380 ops/sLinkedListIterationBenchMark.forIndexIterate thrpt 2 206.866 ops/s
下面我们来详细介绍一下相关的注解
@BenchmarkMode
微基准测试类型。JMH 提供了以下几种类型进行支持:

可以注释在方法级别,也可以注释在类级别,
@BenchmarkMode(Mode.All)public class LinkedListIterationBenchMark {...}@Benchmark@BenchmarkMode({Mode.Throughput, Mode.SingleShotTime})public void m() {...}
@Warmup
这个单词的意思就是预热,iterations = 3就是指预热轮数。
@Benchmark@BenchmarkMode({Mode.Throughput, Mode.SingleShotTime})@Warmup(iterations = 3)public void m() {...}
正式度量计算的轮数。
@Benchmark@BenchmarkMode({Mode.Throughput, Mode.SingleShotTime})@Measurement(iterations = 3)public void m() {...}
每个进程中的测试线程。
@Threads(Threads.MAX)public class LinkedListIterationBenchMark {...}
@Fork
进行 fork 的次数。如果 fork 数是3的话,则 JMH 会 fork 出3个进程来进行测试。
@Benchmark@BenchmarkMode({Mode.Throughput, Mode.SingleShotTime})@Fork(value = 3)public void m() {...}
@OutputTimeUnit
基准测试结果的时间类型。一般选择秒、毫秒、微秒。
@OutputTimeUnit(TimeUnit.SECONDS)public class LinkedListIterationBenchMark {...}
@Benchmark
@Param
@Setup
方法级注解,这个注解的作用就是我们需要在测试之前进行一些准备工作,比如对一些数据的初始化之类的。微信搜索公众号:互联网架构师,回复“2T”,获取更多精品学习资料
@TearDown
@State
启动方法
/*** 仅限于IDE中运行* 命令行模式 则是 build 然后 java -jar 启动** 1. 这是benchmark 启动的入口* 2. 这里同时还完成了JMH测试的一些配置工作* 3. 默认场景下,JMH会去找寻标注了@Benchmark的方法,可以通过include和exclude两个方法来完成包含以及排除的语义*/public static void main(String[] args) throws RunnerException {Options opt = new OptionsBuilder()// 包含语义// 可以用方法名,也可以用XXX.class.getSimpleName().include("Helloworld")// 排除语义.exclude("Pref")// 预热10轮.warmupIterations(10)// 代表正式计量测试做10轮,// 而每次都是先执行完预热再执行正式计量,// 内容都是调用标注了@Benchmark的代码。.measurementIterations(10)// forks(3)指的是做3轮测试,// 因为一次测试无法有效的代表结果,// 所以通过3轮测试较为全面的测试,// 而每一轮都是先预热,再正式计量。.forks(3).output("E:/Benchmark.log").build();new Runner(opt).run();}
相关阅读:2T架构师学习资料干货分享
全栈架构社区交流群
「全栈架构社区」建立了读者架构师交流群,大家可以添加小编微信进行加群。欢迎有想法、乐于分享的朋友们一起交流学习。
看完本文有收获?请转发分享给更多人
往期资源:
评论
