StringAdd, StringBuffer, StringBuilder, StringBuilderHelper性能对比分析
测试环境
硬件
CPU
Intel(R) Core(TM) i5-8265U CPU @ 1.60GHz
基准速度: 1.80 GHz
插槽: 1
内核: 4
逻辑处理器: 8
虚拟化: 已启用
L1 缓存: 256 KB
L2 缓存: 1.0 MB
L3 缓存: 6.0 MB
内存
8.0 GB
速度: 2133 MHz
已使用的插槽: 2/2
外形规格: Row of chips
为硬件保留的内存: 154 MB
软件
IDEA ULTIMATE 2018.3
JMH Benchmark框架 1.21
测试类
/**
* 比较字符串直接相加和StringBuilder的效率
*/
@BenchmarkMode(Mode.AverageTime)
@Warmup(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS)
@State(Scope.Thread)
@Threads(1)
@Fork(1)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public class StringBuilderBenchmark {
private String repeatItem;
private int repeatTimes;
@Setup
public void init() {
repeatItem = "Benchmark";
repeatTimes = 100;
}
@Benchmark
public void stringAdd(Blackhole bh) {
String a = "";
for (int i = 0; i < repeatTimes; i++) {
a += repeatItem;
}
bh.consume(a);
}
@Benchmark
public void stringBufferAdd(Blackhole bh) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < repeatTimes; i++) {
sb.append(repeatItem);
}
bh.consume(sb.toString());
}
@Benchmark
public void stringBuilderAdd(Blackhole bh) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < repeatTimes; i++) {
sb.append(repeatItem);
}
bh.consume(sb.toString());
}
@Benchmark
public void stringBuilderHelperAdd(Blackhole bh) {
StringBuilder sb = StringBuilderHelper.getStringBuilder();
for (int i = 0; i < repeatTimes; i++) {
sb.append(repeatItem);
}
bh.consume(sb.toString());
}
}
public final class StringBuilderHelper {
private static final ThreadLocal<StringBuilder> TLSB = ThreadLocal.withInitial(StringBuilder::new);
private StringBuilderHelper() {
}
public static StringBuilder getStringBuilder() {
StringBuilder stringBuilder = TLSB.get();
stringBuilder.setLength(0);
return stringBuilder;
}
}
生成短字符串
"Benchmark"重复拼接20次
这里取平均耗时,单位微秒,下同。
@Setup
public void init() {
repeatItem = "Benchmark";
repeatTimes = 20;
}
Benchmark Mode Cnt Score Error Units
StringBuilderBenchmark.stringAdd avgt 5 0.406 ± 0.010 us/op
StringBuilderBenchmark.stringBufferAdd avgt 5 0.262 ± 0.005 us/op
StringBuilderBenchmark.stringBuilderAdd avgt 5 0.259 ± 0.033 us/op
StringBuilderBenchmark.stringBuilderHelperAdd avgt 5 0.152 ± 0.020 us/op
"BenchmarkBenchmarkBenchmarkBenchmarkBenchmark"重复拼接20次
@Setup
public void init() {
repeatItem = "BenchmarkBenchmarkBenchmarkBenchmarkBenchmark";
repeatTimes = 20;
}
Benchmark Mode Cnt Score Error Units
StringBuilderBenchmark.stringAdd avgt 5 1.717 ± 0.010 us/op
StringBuilderBenchmark.stringBufferAdd avgt 5 0.861 ± 0.007 us/op
StringBuilderBenchmark.stringBuilderAdd avgt 5 0.846 ± 0.016 us/op
StringBuilderBenchmark.stringBuilderHelperAdd avgt 5 0.249 ± 0.023 us/op
生成中长字符串
"Benchmark"重复拼接100次
@Setup
public void init() {
repeatItem = "Benchmark";
repeatTimes = 100;
}
Benchmark Mode Cnt Score Error Units
StringBuilderBenchmark.stringAdd avgt 5 8.103 ± 0.128 us/op
StringBuilderBenchmark.stringBufferAdd avgt 5 1.198 ± 0.010 us/op
StringBuilderBenchmark.stringBuilderAdd avgt 5 1.113 ± 0.025 us/op
StringBuilderBenchmark.stringBuilderHelperAdd avgt 5 0.663 ± 0.009 us/op
"BenchmarkBenchmarkBenchmarkBenchmarkBenchmark"重复拼接100次
@Setup
public void init() {
repeatItem = "BenchmarkBenchmarkBenchmarkBenchmarkBenchmark";
repeatTimes = 100;
}
Benchmark Mode Cnt Score Error Units
StringBuilderBenchmark.stringAdd avgt 5 38.761 ± 1.753 us/op
StringBuilderBenchmark.stringBufferAdd avgt 5 3.432 ± 0.036 us/op
StringBuilderBenchmark.stringBuilderAdd avgt 5 3.240 ± 0.043 us/op
StringBuilderBenchmark.stringBuilderHelperAdd avgt 5 1.367 ± 0.021 us/op
生成长字符串
"Benchmark"重复拼接1000次
@Setup
public void init() {
repeatItem = "Benchmark";
repeatTimes = 1000;
}
Benchmark Mode Cnt Score Error Units
StringBuilderBenchmark.stringAdd avgt 5 761.627 ± 16.109 us/op
StringBuilderBenchmark.stringBufferAdd avgt 5 10.885 ± 0.144 us/op
StringBuilderBenchmark.stringBuilderAdd avgt 5 10.016 ± 0.179 us/op
StringBuilderBenchmark.stringBuilderHelperAdd avgt 5 7.148 ± 0.107 us/op
"BenchmarkBenchmarkBenchmarkBenchmarkBenchmark"重复拼接1000次
@Setup
public void init() {
repeatItem = "BenchmarkBenchmarkBenchmarkBenchmarkBenchmark";
repeatTimes = 1000;
}
Benchmark Mode Cnt Score Error Units
StringBuilderBenchmark.stringAdd avgt 5 4035.181 ± 59.044 us/op
StringBuilderBenchmark.stringBufferAdd avgt 5 35.703 ± 9.170 us/op
StringBuilderBenchmark.stringBuilderAdd avgt 5 32.452 ± 5.626 us/op
StringBuilderBenchmark.stringBuilderHelperAdd avgt 5 17.628 ± 5.808 us/op
生成超长字符串
"Benchmark"重复拼接10000次
@Setup
public void init() {
repeatItem = "Benchmark";
repeatTimes = 10000;
}
Benchmark Mode Cnt Score Error Units
StringBuilderBenchmark.stringAdd avgt 5 78718.895 ± 1009.605 us/op
StringBuilderBenchmark.stringBufferAdd avgt 5 131.177 ± 37.317 us/op
StringBuilderBenchmark.stringBuilderAdd avgt 5 119.158 ± 21.876 us/op
StringBuilderBenchmark.stringBuilderHelperAdd avgt 5 81.608 ± 5.685 us/op
"BenchmarkBenchmarkBenchmarkBenchmarkBenchmark"重复拼接10000次
@Setup
public void init() {
repeatItem = "BenchmarkBenchmarkBenchmarkBenchmarkBenchmark";
repeatTimes = 10000;
}
Benchmark Mode Cnt Score Error Units
StringBuilderBenchmark.stringAdd avgt 5 704055.930 ± 991698.568 us/op
StringBuilderBenchmark.stringBufferAdd avgt 5 426.180 ± 1.483 us/op
StringBuilderBenchmark.stringBuilderAdd avgt 5 420.615 ± 2.914 us/op
StringBuilderBenchmark.stringBuilderHelperAdd avgt 5 177.804 ± 17.385 us/op
生成超长字符串+多线程
"BenchmarkBenchmarkBenchmarkBenchmarkBenchmark"重复拼接10000次,10个线程
@Threads(10)
@Setup
public void init() {
repeatItem = "BenchmarkBenchmarkBenchmarkBenchmarkBenchmark";
repeatTimes = 10000;
}
Benchmark Mode Cnt Score Error Units
StringBuilderBenchmark.stringAdd avgt 5 6877607.658 ± 68654.544 us/op
StringBuilderBenchmark.stringBufferAdd avgt 5 3792.719 ± 33.263 us/op
StringBuilderBenchmark.stringBuilderAdd avgt 5 3780.851 ± 79.109 us/op
StringBuilderBenchmark.stringBuilderHelperAdd avgt 5 1387.908 ± 67.224 us/op
结果分析
- 短字符串,如"Benchmark"重复 20次,String+的性能是其他三种方法的1/2,差距不是太大。
- 中长字符串开始,如"Benchmark"重复100次,String+的性能被拉开。
- StringBuffer和StringBuilder在单线程场景下,性能非常接近,后者略优。
- StringBuilderHelper(ThreadLocal版的StringBuilder)是性能最好的版本,尤其是大颗粒大字符串情况下("BenchmarkBenchmarkBenchmarkBenchmarkBenchmark"重复10000次对比"Benchmark"重复10000次),相较于StringBuilder和StringBuffer的性能,提升一倍多。
- StringBuilderHelper在线程池下的效率会更高(因为线程不销毁,StringBuilder实例不会被销毁,能够最大程度复用)。
网友评论