Java String拼接性能分析

StringAdd, StringBuffer, StringBuilder, StringBuilderHelper性能對(duì)比分析

測(cè)試環(huán)境

硬件

CPU

Intel(R) Core(TM) i5-8265U CPU @ 1.60GHz

基準(zhǔn)速度:   1.80 GHz
插槽: 1
內(nèi)核: 4
邏輯處理器:  8
虛擬化:    已啟用
L1 緩存:  256 KB
L2 緩存:  1.0 MB
L3 緩存:  6.0 MB

內(nèi)存

8.0 GB

速度: 2133 MHz
已使用的插槽: 2/2
外形規(guī)格:   Row of chips
為硬件保留的內(nèi)存:   154 MB

軟件

IDEA ULTIMATE 2018.3
JMH Benchmark框架 1.21

測(cè)試類(lèi)

/**
 * 比較字符串直接相加和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"重復(fù)拼接20次

這里取平均耗時(shí),單位微秒,下同。

@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"重復(fù)拼接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

生成中長(zhǎng)字符串

"Benchmark"重復(fù)拼接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"重復(fù)拼接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

生成長(zhǎng)字符串

"Benchmark"重復(fù)拼接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"重復(fù)拼接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

生成超長(zhǎng)字符串

"Benchmark"重復(fù)拼接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"重復(fù)拼接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

生成超長(zhǎng)字符串+多線程

"BenchmarkBenchmarkBenchmarkBenchmarkBenchmark"重復(fù)拼接10000次,10個(gè)線程

@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

結(jié)果分析

  • 短字符串,如"Benchmark"重復(fù) 20次,String+的性能是其他三種方法的1/2,差距不是太大。
  • 中長(zhǎng)字符串開(kāi)始,如"Benchmark"重復(fù)100次,String+的性能被拉開(kāi)。
  • StringBuffer和StringBuilder在單線程場(chǎng)景下,性能非常接近,后者略優(yōu)。
  • StringBuilderHelper(ThreadLocal版的StringBuilder)是性能最好的版本,尤其是大顆粒大字符串情況下("BenchmarkBenchmarkBenchmarkBenchmarkBenchmark"重復(fù)10000次對(duì)比"Benchmark"重復(fù)10000次),相較于StringBuilder和StringBuffer的性能,提升一倍多。
  • StringBuilderHelper在線程池下的效率會(huì)更高(因?yàn)榫€程不銷(xiāo)毀,StringBuilder實(shí)例不會(huì)被銷(xiāo)毀,能夠最大程度復(fù)用)。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 12月6-7日,團(tuán)委在相城和東山校區(qū)開(kāi)展了主題為 “青春奉獻(xiàn)美麗中國(guó)夢(mèng),團(tuán)聚共繪青春蘇農(nóng)圖” 特別團(tuán)日活動(dòng)。園藝科...
    泗水留年閱讀 598評(píng)論 0 0
  • 成都,我的第二故鄉(xiāng)。我的故鄉(xiāng)她不美,該怎么形容她呢? 大概是2005年,第一次來(lái)成都。懷著各種心情,除了點(diǎn)點(diǎn)恐懼,...
    了夢(mèng)一川閱讀 307評(píng)論 0 1
  • 如果夜色沉寂 是否能夠拾起 夕陽(yáng)里的記憶 字字端祥,事無(wú)巨細(xì) 如果愛(ài)有天意 能否不再背離 傾注一生的意義 故事柔軟...
    子觀閱讀 250評(píng)論 0 3
  • 我是一個(gè)九零后,同時(shí)我也是個(gè)淘寶店主。我從一個(gè)連開(kāi)店流程都要靠百度的小白賣(mài)家。到月賺三萬(wàn)多的小資賣(mài)家。 對(duì)的,我的...
    輕奢女王閱讀 682評(píng)論 0 0

友情鏈接更多精彩內(nèi)容