性能测试JMH
说在前面
StringBuilder和String谁快?快多少?为什么在大量字符拼接要用StringBuilder?
取模和并计算谁快?快多少?为什么大部分开源项目都采用并计算替换取模?
你在开发中是否也遇到如上的问题,以上当然只是技术海洋的冰山一角,你在工作中,学习中遇到类似的问题数不胜数
不知道多少人像我一样,看看技术爽文,心里虽然也知道StringBulder当然比String快啦,毕竟String会不停的创建中间对象,并计算当然比取模快拉,毕竟二进制运算是最快的
但是久而久之,我们都逐渐沦为 “的司机”,仅仅停留在表面,没有用真正的数据来量化比较过它们,又怎么会理解其底层设计的精华,更不会想着去做优化
但是有人会说了,要是每针对这样的场景都要自己去写个测试用例,成本过高而且考虑的方向比较狭隘,导致结果也不清不楚
因此在这里要给大家介绍一个工具JMH,帮助大家通过量化的数据来进行比较,从而告别含糊不清的描述,相信这是每个极客或者数据人的追求
生成视图的网站(在跑性能测试时指定生成json格式的结果,再上传到此网站可视化):
http://deepoove.com/jmh-visual-chart/ (效果相对较好,但是偶尔会故障)
https://jmh.morethan.io/
实战
注:JDK9后自带JMK
- 添加pom依赖
<!-- JMH-->
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>1.25.2</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>1.25.2</version>
<scope>provided</scope>
</dependency>
- 增加性能测试类,在需要做性能测试的方法上添加@Benchnmark注解
场景:验证字符串拼接的性能差异
@BenchmarkMode(Mode.Throughput)
@Warmup(iterations = 3)
@Measurement(iterations = 10, time = 5, timeUnit = TimeUnit.SECONDS)
@Threads(8)
@Fork(2)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
public class StringBuilderBenchmark {
@Benchmark
public void testStringAdd() {
String a = "";
for (int i = 0; i < 1000; i++) {
a += i;
}
print(a);
}
@Benchmark
public void testStringBuilderAdd() {
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < 1000; i++) {
stringBuilder.append(i);
}
print(stringBuilder.toString());
}
private void print(String a) {
}
// 生成json格式的结果,默认是生成log格式的
public static void main(String []args) throws RunnerException {
org.openjdk.jmh.runner.options.Options options = new OptionsBuilder()
.include(StringBuilderBenchmark.class.getSimpleName())
.shouldDoGC(true)
.resultFormat(ResultFormatType.JSON)
.result("benchmark-result.json")
.addProfiler(StackProfiler.class)
.jvmArgsAppend("-Djmh.stack.period=1")
.warmupIterations(5)
.measurementIterations(5)
.forks(1)
.build();
new Runner(options).run();
}
}
如下图可见,String的1000此拼接耗时大约为0.6 ms,约为StringBuilder的6倍,因此在做字符串拼接时,我们应优先考虑StringBuilder

由以下分析可知,在拼接10,50,100个字符时,使用String和StringBuilder每秒分别可操作的次数


浙公网安备 33010602011771号