[轉載] 整理下java中stringBuilder和stringBuffer兩個類的區別

ld909發表於2020-12-12

參考連結: Java中的StringBuffer類

StringBuilder和StringBuffer這兩個類在動態拼接字串時常用,肯定比String的效率和開銷小,這是因為String的物件不會回收哦。 

 其實我一直用StringBuilder這個類,因為可以簡寫為sb的變數在程式裡很爽,可是後來師兄說web程式特別是高併發的程式中不要用stringbuilder,因為簡單說,stringBuilder不是執行緒安全的,而StirngBuffer就是執行緒安全的。從網上看到Stringbuffer中方法大都採用了synchronized的關鍵字修飾。 

 來來來,我們先複習下syncronized的用法,有篇部落格寫的挺好的,給個連結 http://leo-faith.iteye.com/blog/177779 

  

 

  1、synchronized關鍵字的作用域有二種: 1)是某個物件例項內,synchronized aMethod(){}可以防止多個執行緒同時訪問這個物件的synchronized方法(如果一個物件有多個synchronized方法,只要一個執行緒訪問了其中的一個synchronized方法,其它執行緒不能同時訪問這個物件中任何一個synchronized方法)。這時,不同的物件例項的synchronized方法是不相干擾的。也就是說,其它執行緒照樣可以同時訪問相同類的另一個物件例項中的synchronized方法; 2)是某個類的範圍,synchronized static aStaticMethod{}防止多個執行緒同時訪問這個類中的synchronized static 方法。它可以對類的所有物件例項起作用。

 

   

 

  2、除了方法前用synchronized關鍵字,synchronized關鍵字還可以用於方法中的某個區塊中,表示只對這個區塊的資源實行互斥訪問。用法是: synchronized(this){/*區塊*/},它的作用域是當前物件;

 

 

 

  3、synchronized關鍵字是不能繼承的,也就是說,基類的方法synchronized f(){} 在繼承類中並不自動是synchronized f(){},而是變成了f(){}。繼承類需要你顯式的指定它的某個方法為synchronized方法;

 

 好了,言歸正傳,我們繼續StringBuffer和StringBuilder的區別。 

 就是說,StringBuffer中所有的方法都要加鎖,所以好多操作看上去都是線性操作的。所以要慢些。 

  

 

  一般情況下,速度從快到慢:StringBuilder>StringBuffer>String.當需要在迴圈中多次使用字串拼接時,建議使用StringBuilder或StringBuffer.當數量級在百萬級(這裡可能不準確)時,StringBuilder的速度會體現出來.

 

 

以下是實驗資料 

  

  

 

  

   

    01 final static int ttime = 30000;// 測試迴圈次數 

   

   

    02   

   

   

    03     public void test(String s) { 

   

   

    04         long begin = System.currentTimeMillis(); 

   

   

    05         for (int i = 0; i < ttime; i++) { 

   

   

    06             s += "add"; 

   

   

    07         } 

   

   

    08         long over = System.currentTimeMillis(); 

   

   

    09         System.out.println(" 操作 " + s.getClass().getName() + " 型別使用的時間為: " + (over - begin) + " 毫秒 "); 

   

   

    10     } 

   

   

    11   

   

   

    12     public void test(StringBuffer s) { 

   

   

    13         long begin = System.currentTimeMillis(); 

   

   

    14         for (int i = 0; i < ttime; i++) { 

   

   

    15             s.append("add"); 

   

   

    16         } 

   

   

    17         long over = System.currentTimeMillis(); 

   

   

    18         System.out.println(" 操作 " + s.getClass().getName() + " 型別使用的時間為: " + (over - begin) + " 毫秒 "); 

   

   

    19     } 

   

   

    20   

   

   

    21     public void test(StringBuilder s) { 

   

   

    22         long begin = System.currentTimeMillis(); 

   

   

    23         for (int i = 0; i < ttime; i++) { 

   

   

    24             s.append("add"); 

   

   

    25         } 

   

   

    26         long over = System.currentTimeMillis(); 

   

   

    27         System.out.println(" 操作 " + s.getClass().getName() + " 型別使用的時間為: " + (over - begin) + " 毫秒 "); 

   

   

    28     } 

   

   

    29   

   

   

    30     // 對 String 直接進行字串拼接的測試 

   

   

    31     public void test2() { 

   

   

    32         String s2 = "abadf"; 

   

   

    33         long begin = System.currentTimeMillis(); 

   

   

    34         for (int i = 0; i < ttime; i++) { 

   

   

    35             String s = s2 + s2 + s2; 

   

   

    36         } 

   

   

    37         long over = System.currentTimeMillis(); 

   

   

    38         System.out.println(" 操作字串物件引用相加型別使用的時間為: " + (over - begin) + " 毫秒 "); 

   

   

    39     } 

   

   

    40   

   

   

    41     public void test3() { 

   

   

    42         long begin = System.currentTimeMillis(); 

   

   

    43         for (int i = 0; i < ttime; i++) { 

   

   

    44             String s = "abadf" + "abadf" + "abadf"; 

   

   

    45         } 

   

   

    46         long over = System.currentTimeMillis(); 

   

   

    47         System.out.println(" 操作字串相加使用的時間為: " + (over - begin) + " 毫秒 "); 

   

   

    48     } 

   

   

    49   

   

   

    50     public static void main(String[] args) { 

   

   

    51         String s1 = "abc"; 

   

   

    52         StringBuffer sb1 = new StringBuffer("abc"); 

   

   

    53         StringBuilder sb2 = new StringBuilder("abc"); 

   

   

    54         Test t = new Test(); 

   

   

    55         t.test(s1); 

   

   

    56         t.test(sb1); 

   

   

    57         t.test(sb2); 

   

   

    58         t.test2(); 

   

   

    59         t.test3(); 

   

   

    60     } 

   

  

 

  

試驗結果如下: 

  

  

  操作 java.lang.String 型別使用的時間為: 2432 毫秒  

  操作 java.lang.StringBuffer 型別使用的時間為: 3 毫秒  

  操作 java.lang.StringBuilder 型別使用的時間為: 3 毫秒  

  操作字串物件引用相加型別使用的時間為: 6 毫秒  

  操作字串相加使用的時間為: 1 毫秒  

  

 把迴圈次數調的很大,試了用下jconsle來監視記憶體GC,第一次使用,不太明白,有個部落格寫的很好的,有空研究一下 

  http://jiajun.iteye.com/blog/810150 

 再補充一個Jstat的工具 http://xiaolele.iteye.com/blog/592022 

 /** 

 *20120516昨天忘看原始碼了 

 **/ 

 StringBuffer中append方法有很多過載,有synchronized關鍵字沒錯,主要呼叫的還是AbstractStringBuilder的super的方法。 

  

 

  

   

    1 public synchronized StringBuffer append(String s) 

   

   

    2 { 

   

   

    3     super.append(s); 

   

   

    4     return this; 

   

   

    5 } 

   

  

 

  

父類的方法為 

  

 

  

   

    01 public AbstractStringBuilder append(String s) { 

   

   

    02   

   

   

    03     if (s == null) 

   

   

    04         s = "null"; 

   

   

    05     int i = s.length(); 

   

   

    06     if (i == 0) 

   

   

    07         return this; 

   

   

    08     int j = count + i; 

   

   

    09     if (j > value.length) 

   

   

    10         expandCapacity(j); 

   

   

    11     s.getChars(0, i, value, count); 

   

   

    12     count = j; 

   

   

    13     return this; 

   

   

    14 } 

   

  

 

  

  

 StringBuilder類中的append就沒有同步的關鍵字了。父類的方法基本上差不多。 

 總結一下,StringBuffer執行緒安全,內部有synchronized方法,StringBuilder是1.5之後出來的,高併發就不要用了。另外synchronized的使用要熟悉,以後研究下java記憶體的工具,比如jconsle。 

   

 轉載:http://my.oschina.net/zimingforever/blog/57514

相關文章