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

String vs StringBuffer vs StringBuilder:字符串操作性能與線程安全終極對決

     編輯:Java 程式設計入門

核心結論先行

單線程高頻修改:StringBuilder > StringBuffer > String
多線程共享:StringBuffer > StringBuilder(需外部同步)
常量拼接/少量操作:String 編譯器優化極快

三大類核心機制對比

特性StringStringBufferStringBuilder
可變性不可變可變可變
線程安全天然安全(不可變)同步方法,線程安全非同步,非線程安全
底層結構final char[] / byte[]可擴容 char[] / byte[]可擴容 char[] / byte[]
拼接操作產生新對象原地修改原地修改
JDK 版本1.01.05.0
性能排序最低 (頻繁修改時)中等 (同步開銷)最高 (無同步)

String 不可變的性能代價


String s = "abc";
for (int i = 0; i < 10000; i++) {
    s += "def"; // 每次循環:新建 StringBuilder → append → toString → 新 String 對象
    s = "abc";  // 10000 次循環 ≈ 20000+ 臨時對象 → GC 壓力大
}

內存震盪:大量短命對象觸發 Minor GC,甚至 Full GC,嚴重影響吞吐量。

JVM 隱藏優化:常量折疊


// 源碼
String s = "This is only a" + " simple" + " test";

// 編譯器優化後 (javap -c 可見)
String s = "This is only a simple test"; // 編譯期常量折疊,零運行開銷

但變量拼接無優化:


String a = "This is only a";
String b = " simple";
String c = " test";
String s = a + b + c; // 運行期 StringBuilder 拼接,有開銷

StringBuffer 同步機制解析


public synchronized void append(String str) {
    toStringCache = null;
    super.append(str);
}

每次 append 加鎖,單線程下純粹開銷。JDK 5 引入 StringBuilder 專門解決此痛點。

實戰基準測試代碼


public class ConcatBenchmark {
    static final int LOOPS = 100_000;
    
    public static void main(String[] args) {
        // String +=
        long t1 = System.currentTimeMillis();
        String s = "";
        for (int i = 0; i < LOOPS; i++) s += "x";
        System.out.println("String += : " + (System.currentTimeMillis() - t1) + "ms");
        
        // StringBuffer
        long t2 = System.currentTimeMillis();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < LOOPS; i++) sb.append("x");
        System.out.println("StringBuffer: " + (System.currentTimeMillis() - t2) + "ms");
        
        // StringBuilder
        long t3 = System.currentTimeMillis();
        StringBuilder sbl = new StringBuilder();
        for (int i = 0; i < LOOPS; i++) sbl.append("x");
        System.out.println("StringBuilder: " + (System.currentTimeMillis() - t3) + "ms");
    }
}
// 典型輸出 (單線程):
// String += : 4500ms+
// StringBuffer: 15ms
// StringBuilder: 8ms

回文判斷實戰:StringBuilder 反轉優勢


// 方案一:雙指針遍歷 String (不創建新對象)
public boolean isPalindrome(String s) {
    int l = 0, r = s.length() - 1;
    while (l < r) if (s.charAt(l++) != s.charAt(r--)) return false;
    return true;
}

// 方案二:StringBuilder 反轉比較 (代碼極簡)
public boolean isPalindromeSB(String s) {
    return s.equals(new StringBuilder(s).reverse().toString());
}

// 方案三:過濾非字母數字後判斷
public boolean isPalindromeFiltered(String s) {
    StringBuilder filtered = new StringBuilder();
    for (char c : s.toCharArray()) 
        if (Character.isLetterOrDigit(c)) filtered.append(c);
    String clean = filtered.toString();
    return clean.equals(new StringBuilder(clean).reverse().toString());
}

選型決策樹


需要頻繁修改字符串?
├── 多線程共享實例? ──▶ StringBuffer
└── 單線程/線程封閉? ──▶ StringBuilder (首選)
只有少量拼接/常量拼接? ──▶ String (編譯器優化)
需不可變/作為 Map Key? ──▶ String

總結

StringBuilder 是 JDK 5 為單線程高性能場景定制的「去同步版 StringBuffer」。現代開發中,默認選 StringBuilder,僅在多線程直接共享緩衝區時用 StringBuffer,利用編譯器常量折疊優化靜態拼接。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved