为了评测 jdk 8、jdk11、jdk16 以及 jdk17 的性能,我准备做下基准测试,于是有了此文。
首先,添加依赖:

<!-- https://mvnrepository.com/artifact/org.openjdk.jmh/jmh-core -->
<dependency>
    <groupId>org.openjdk.jmh</groupId>
    <artifactId>jmh-core</artifactId>
    <version>1.35</version>
    <scope>test</scope>
</dependency>

<!-- https://mvnrepository.com/artifact/org.openjdk.jmh/jmh-generator-annprocess -->
<dependency>
    <groupId>org.openjdk.jmh</groupId>
    <artifactId>jmh-generator-annprocess</artifactId>
    <version>1.35</version>
    <scope>test</scope>
</dependency>

然后,我们来看下我的测试类:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;
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 org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.concurrent.TimeUnit;

@BenchmarkMode({Mode.Throughput})
@OutputTimeUnit(TimeUnit.SECONDS)
@Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Fork(0)
@State(Scope.Benchmark)
@RunWith(SpringRunner.class)
@SpringBootTest(classes = NacosApplication.class)
public class JMHFirstBenchmarkTests {

    private static LibApi libApi;

    private static ConfigService configService;

    @Autowired
    public void SetLibApi(LibApi libApi) {
        JMHFirstBenchmarkTests.libApi = libApi;
    }

    @Autowired
    public void setConfigService(ConfigService configService) {
        JMHFirstBenchmarkTests.configService = configService;
    }

    @Benchmark
    public void sayHello(Blackhole blackhole) {
        CommonResult<AppConfig> result = libApi.allConfig("shopline-utils-pressure", "test", "chun");
        blackhole.consume(result);
    }

    @Test
    public void runBenchmarks() throws RunnerException {
        Options opts = new OptionsBuilder()
                .include("\\." + this.getClass().getSimpleName() + "\\.")
                .shouldFailOnError(true)
                .resultFormat(ResultFormatType.JSON)
                .jvmArgs("-server")
                .build();

        new Runner(opts).run();
    }
}

这里,古怪的可能是 以下几行代码:

    private static LibApi libApi;

    private static ConfigService configService;

    @Autowired
    public void SetLibApi(LibApi libApi) {
        JMHFirstBenchmarkTests.libApi = libApi;
    }

    @Autowired
    public void setConfigService(ConfigService configService) {
        JMHFirstBenchmarkTests.configService = configService;
    }

其实,这里就是需要这样写,不然在 @Test 注解中,libApi 以及 configService 不为 null,但是在 @Benchmark 中,则为 null,所以这里这样处理了下。
idea 不装 jmh 的插件也OK,输出结果大致如下:

Result "xxx.xxx.xxx.xxx.JMHFirstBenchmarkTests.sayHello":
  9762.216 ±(99.9%) 1000.228 ops/s [Average]
  (min, avg, max) = (9409.331, 9762.216, 10008.253), stdev = 259.756
  CI (99.9%): [8761.988, 10762.443] (assumes normal distribution)


# Run complete. Total time: 00:00:10

REMEMBER: The numbers below are just data. To gain reusable insights, you need to follow up on
why the numbers are the way they are. Use profilers (see -prof, -lprof), design factorial
experiments, perform baseline and negative tests that provide experimental control, make sure
the 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.

NOTE: Current JVM experimentally supports Compiler Blackholes, and they are in use. Please exercise
extra caution when trusting the results, look into the generated code to check the benchmark still
works, and factor in a small probability of new VM bugs. Additionally, while comparisons between
different JVMs are already problematic, the performance difference caused by different Blackhole
modes can be very significant. Please make sure you use the consistent Blackhole mode for comparisons.

Benchmark                         Mode  Cnt     Score      Error  Units
JMHFirstBenchmarkTests.sayHello  thrpt    5  9762.216 ± 1000.228  ops/s

从测试结果看,qps 达到了 9762,看最上面的 avg 即可。