BenchMark 又叫做基准测试,主要用来测试一些方法的性能,可以根据不同的参数以不同的单位进行计算(例如可以使用吞吐量为单位,也可以使用平均时间作为单位,在 BenchmarkMode 里面进行调整)。
依赖
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>1.19</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>1.19</version>
<scope>provided</scope>
</dependency>
使用示例
ArrayList 和 LinkedList 的遍历的性能差别
package com.demo;
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.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeUnit;
@BenchmarkMode(Mode.Throughput) // 吞吐量
@OutputTimeUnit(TimeUnit.MILLISECONDS) // 结果所使用的时间单位
@State(Scope.Thread) // 每个测试线程分配一个实例
@Fork(2) // Fork进行的数目
@Warmup(iterations = 4) // 先预热4轮
@Measurement(iterations = 10) // 进行10轮测试
public class BenchMarkDemo {
@Param({
"10", "40", "70", "100"}) // 定义四个参数,之后会分别对这四个参数进行测试
private int n;
private List<Integer> array;
private List<Integer> list;
@Setup(Level.Trial) // 初始化方法,在全部Benchmark运行之前进行
public void init() {
array = new ArrayList<>(0);
list = new LinkedList<>();
for (int i = 0; i < n; i++) {
array.add(i);
list.add(i);
}
}
@Benchmark
public void arrayTraverse() {
for (int i = 0; i < n; i++) {
array.get(i);
}
}
@Benchmark
public void listTraverse() {
for (int i = 0; i < n; i++) {
list.get(i);
}
}
@TearDown(Level.Trial) // 结束方法,在全部Benchmark运行之后进行
public void arrayRemove() {
for (int i = 0; i < n; i++) {
array.remove(0);
list.remove(0);
}
}
public static void main(String[] args) throws RunnerException {
Options options = new OptionsBuilder().include(BenchMarkDemo.class.getSimpleName()).build();
new Runner(options).run();
}
}
# Run complete. Total time: 00:03:56
Benchmark (n) Mode Cnt Score Error Units
BenchMarkDemo.arrayTraverse 10 thrpt 20 337852.300 ± 10230.514 ops/ms
BenchMarkDemo.arrayTraverse 40 thrpt 20 342619.598 ± 6272.177 ops/ms
BenchMarkDemo.arrayTraverse 70 thrpt 20 342534.411 ± 6018.479 ops/ms
BenchMarkDemo.arrayTraverse 100 thrpt 20 333470.068 ± 17285.845 ops/ms
BenchMarkDemo.listTraverse 10 thrpt 20 45899.695 ± 2960.264 ops/ms
BenchMarkDemo.listTraverse 40 thrpt 20 6615.649 ± 201.404 ops/ms
BenchMarkDemo.listTraverse 70 thrpt 20 1910.175 ± 31.484 ops/ms
BenchMarkDemo.listTraverse 100 thrpt 20 787.424 ± 25.747 ops/ms
可以结合 Score 和 Unit 这两列,看到方法的效率。这里显然 arrayTraverse 的效率比 listTraverse 的高很多,因为 Unit 单位是 ops/ms,即单位时间内执行的操作数。所以显然在遍历的时候,ArrayList的效率是比LinkedList高的。