首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 程式設計入門

StringBuilder vs StringBuffer vs String:效能、線程安全與選型完整指南

     編輯:Java 程式設計入門

字串拼接是 Java 高頻操作,但 String、StringBuilder、StringBuffer 三者效能差 10~100 倍、線程安全性截然不同。本文從 JVM 記憶體模型、源碼實現、基準測試三維度,給出毫無疑慮的選型標準。

核心差異一覽

維度StringStringBuilderStringBuffer
可變性不可變可變可變
線程安全天然安全 (不可變)非安全安全 (synchronized)
底層結構final char[] / byte[]char[] / byte[] (擴容)char[] / byte[] (擴容)
擴容策略每次新建物件1.5 倍 + 11.5 倍 + 1
JDK 版本1.05.0 (取代 StringBuffer)1.0
相對效能 (單執行緒)1x (基準)~50-100x~30-50x (同步開銷)

JVM 記憶體視角:為何 String 效能最差?

String s = "a";
s += "b"; // 實際發生:
// 1. new StringBuilder()
// 2. append("a")
// 3. append("b")
// 4. toString() → 新 String 物件
// 5. 原 "a" 變垃圾

循環拼接 N 次 → 產生 N 個中間 StringBuilder + N 個 String,GC 壓力極大。

源碼級差異:synchronized 關鍵字

// StringBuffer (JDK 17)
@Override
public synchronized StringBuffer append(String str) {
    toStringCache = null;
    super.append(str);
    return this;
}

// StringBuilder (JDK 17)
@Override
public StringBuilder append(String str) {
    toStringCache = null;
    super.append(str);
    return this;
}

StringBuffer 每個方法加 synchronized,單執行緒下純粹增加鎖開銷 (CAS/偏向鎖優化後仍可測)。

JMH 基準測試 (10 萬次拼接,單執行緒)

@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
public class StringConcatBenchmark {

    @Benchmark
    public void stringConcat() {
        String s = "";
        for (int i = 0; i < 100_000; i++) s += "x";
    }

    @Benchmark
    public void builderConcat() {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < 100_000; i++) sb.append("x");
    }

    @Benchmark
    public void bufferConcat() {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < 100_000; i++) sb.append("x");
    }
}

典型結果 (ms/op):

  • stringConcat:~12,000 µs
  • bufferConcat:~180 µs
  • builderConcat:~120 µs

StringBuilder 比 StringBuffer 快 ~30%,比 String 快 ~100 倍。

選型決策樹

需要拼接字串?
├─ 單執行緒 / 區域變數 / 高頻 → StringBuilder (首選)
├─ 多執行緒共享實例 → StringBuffer
├─ 少量拼接 / 常量 / 鍵值 → String (+ 足夠)
└─ 函數式風格 / Stream → Collectors.joining()

進階技巧

1. 預估容量避免擴容

// 預估最終長度 ~2000 字元
StringBuilder sb = new StringBuilder(2048); 

2. Java 8+ Stream 收集器

String result = list.stream()
                    .map(Object::toString)
                    .collect(Collectors.joining(", ")); // 內部用 StringBuilder

3. 字串常量池與 intern()

String s1 = "a" + "b";        // 編譯期常量折疊 → "ab" (池中)
String s2 = new String("ab"); // 堆中新物件
s2.intern();                  // 手動入池,返回池中引用

總結

  • 99% 場景用 StringBuilder:單執行緒、高效能、無同步開銷
  • 僅多執行緒共享緩衝區用 StringBuffer:舊版 API 相容、極少見
  • 簡單拼接、常量、鍵值用 String:可讀性優先、JIT 會優化
  • 預估容量 可再提升 10~20% 效能
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved