(一)、JMH概述
1.什么是JMH?
JMH(Java Microbenchmark Harness)是一个 Java 工具,用于构建、运行和分析用 Java 和其他针对 JVM 的语言编写的 纳米/微米/毫/宏观 基准测试,而且是由Java虚拟机团队开发的。简单说,就是用来测量代码运行性能,简称 :“Java性能检测工具”。
JMH官网:https://openjdk.org/projects/code-tools/jmh/
JMH源码下载:https://github.com/openjdk/jmh
2.JMH入门操作
(1).没有JMH的时候我们怎么进行测试的?
我们利用结束的时间戳 - 结束后的时间戳
@Test void contextLoads() { long l1 = System.currentTimeMillis(); int n=0; for (int i = 1; i <100000 ; i++) { n+=1; } System.out.println(n); long l2 = System.currentTimeMillis(); System.out.println("一共消耗时间: "+(l2-l1)); }
(2).利用JMH进行测试
添加依赖
<dependencies> <dependency> <groupId>org.openjdk.jmh</groupId> <artifactId>jmh-core</artifactId> <version>1.23</version> </dependency> <dependency> <groupId>org.openjdk.jmh</groupId> <artifactId>jmh-generator-annprocess</artifactId> <version>1.23</version> </dependency> <!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all --> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.5</version> </dependency> </dependencies>
(二)、JMH运用展示
1.Hello JMH
源码
package org.openjdk.jmh.samples; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.RunnerException; import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; public class JMHSample_01_HelloWorld { @Benchmark //代表我们现在执行测试的就是这个空方法 public void wellHelloThere() { // // this method was intentionally left blank. } public static void main(String[] args) throws RunnerException { Options opt = new OptionsBuilder() .include(JMHSample_01_HelloWorld.class.getSimpleName()) //执行测试方法的载体类是什么。 .forks(1) //总共测试几轮,默认我们呢选择1 .build(); new Runner(opt).run(); //执行 } }
解释
(三)、JMH注解
1.@Warmip和@Measurement (预热和真实执行)【类】
@Warmip 预热
预热: 执行一次,一次1秒
@Warmup(iterations = 1,time = 1,timeUnit = TimeUnit.SECONDS) //预热次数和时间
真实测试执行一次,一次一秒
@Measurement(iterations = 1,time = 1,timeUnit = TimeUnit.SECONDS) //测试次数和时间
源码
package org.openjdk.jmh.samples; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.Measurement; import org.openjdk.jmh.annotations.Warmup; import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.RunnerException; import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; import java.util.concurrent.TimeUnit; @Warmup(iterations = 1,time = 1,timeUnit = TimeUnit.SECONDS) //预热次数和时间 @Measurement(iterations = 1,time = 1,timeUnit = TimeUnit.SECONDS) //测试次数和时间 public class JMHSample_01_HelloWorld { @Benchmark //代表我们现在执行测试的就是这个空方法 public void wellHelloThere() { // // this method was intentionally left blank. } public static void main(String[] args) throws RunnerException { Options opt = new OptionsBuilder() .include(JMHSample_01_HelloWorld.class.getSimpleName()) .forks(1) .build(); new Runner(opt).run(); } }
2.@BenchmarkMode和@OutputTimeUnit (输出方式和输出单位)【方法】
源码
@BenchmarkMode(Mode.Throughput) //吞吐量测试, 输出报告: 每单位时间会执行多少次 @OutputTimeUnit(TimeUnit.SECONDS) //输出报告的时间单位
package org.openjdk.jmh.samples; import org.openjdk.jmh.annotations.*; import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.RunnerException; import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; import java.util.concurrent.TimeUnit; @Warmup(iterations = 1,time = 1,timeUnit = TimeUnit.SECONDS) //预热次数和时间 @Measurement(iterations = 1,time = 1,timeUnit = TimeUnit.SECONDS) //测试次数和时间 public class JMHSample_02_BenchmarkModes { @Benchmark //执行测试的方法 @BenchmarkMode(Mode.Throughput) //吞吐量测试, 输出报告: 每单位时间会执行多少次 @OutputTimeUnit(TimeUnit.SECONDS) //输出报告的时间单位 public void measureThroughput() throws InterruptedException { TimeUnit.MILLISECONDS.sleep(100); } @Benchmark @BenchmarkMode(Mode.AverageTime) //平均耗时测试, 输出报告每次操作耗时 @OutputTimeUnit(TimeUnit.SECONDS) //耗时的单位 public void measureAvgTime() throws InterruptedException { TimeUnit.MILLISECONDS.sleep(100); } @Benchmark @BenchmarkMode(Mode.SampleTime) //抽样测试,输出报告: 会在执行过程中采样(每次操作耗时) @OutputTimeUnit(TimeUnit.SECONDS) public void measureSamples() throws InterruptedException { TimeUnit.MILLISECONDS.sleep(100); } @Benchmark @BenchmarkMode(Mode.SingleShotTime) //冷启动测试,设置这个,此方法在一轮中只运行一次,这个模式主要是为了测试冷启动的性能 @OutputTimeUnit(TimeUnit.SECONDS) //输出单位 public void measureSingleShot() throws InterruptedException { TimeUnit.MILLISECONDS.sleep(100); } @Benchmark @BenchmarkMode({Mode.Throughput, Mode.AverageTime, Mode.SampleTime, Mode.SingleShotTime}) // 前四种都进行测试。四种模式都会测试一次,输出四种报告 @OutputTimeUnit(TimeUnit.SECONDS) public void measureMultiple() throws InterruptedException { TimeUnit.MILLISECONDS.sleep(100); } @Benchmark @BenchmarkMode(Mode.All) // 不可以像第五种一样指定多种测试方法。只能测试全部四种 @OutputTimeUnit(TimeUnit.SECONDS) public void measureAll() throws InterruptedException { TimeUnit.MILLISECONDS.sleep(100); } public static void main(String[] args) throws RunnerException { Options opt = new OptionsBuilder() .include(JMHSample_02_BenchmarkModes.class.getSimpleName()) .forks(1) .build(); new Runner(opt).run(); } }
第一个测试
第二个测试
第三个测试
第四次测试
第五次测试
第六次测试