大家都知道,StringBuilder和StringBuffer主要區別是前者不是線程安全的,後者是線程安全的,餘JDK預留的對外接口幾乎是一模一樣的,所以在確定線程安全的環境的前提下,優先使用SringBuilder,肯定不相同條件下的StringBuffer性能要高,因爲那維護同步數據的正確性肯定要消耗資源的。
然而在今天的事業部代碼質量報告會上,我在講解StringBuilder和StirngBuffer的區別以及爲什麼優於“+”拼接字符串時候,一位經驗豐富的前輩指點了一下說StringBuilder儘管在拼接字符串時效率高於StringBuffer,但是最終還是好轉成String類型的,而在大字符串拼接的情況下StringBuffer的toString()要比StringBuilder的toString()執行速度將近快3.5倍,所以線程安全的情況下還是用StringBuffer,當時聽了很是高心,因爲自己不知道這個地方,又漲姿勢了。
晚上自己想一探究竟,看了2個類的重寫toString()方法的源碼除了加了同步鎖之外,都是return New String(value,offset,count),納了悶了,都是底層都是調用的同一個方法,反而怎麼是同步的StringBuffer效率高呢,不行,自己寫了一個測試程序,來單獨驗證一下2個toString的效率:
package StringBuilderBufferTest;
public class ToStringPerformanceTest {
public static void main(String[] args){
long start1=System.nanoTime();
StringBuffer strBuffer=new StringBuffer(10000);
for(int i=0;i<10000;i++){
strBuffer.append("a");
}
String testStr1=strBuffer.toString();
long end1=System.nanoTime();
System.out.println("相同字符串StringBuffer拼接並轉成string耗時"+(end1-start1)/1000+"微秒");
long start2=System.nanoTime();
StringBuilder strBuilder=new StringBuilder(10000);
for(int i=0;i<10000;i++){
strBuilder.append("a");
}
String testStr2=strBuffer.toString();
long end2=System.nanoTime();
System.out.println("相同字符串StringBuilder拼接並轉成string耗時"+(end2-start2)/1000+"微秒");
StringBuffer buffer=new StringBuffer(testStr1);
StringBuilder builder=new StringBuilder(testStr1);
long start3=System.nanoTime();
String s3=buffer.toString();
long end3=System.nanoTime();
System.out.println("相同字符串單純StringBuffer.toString()耗時"+(end3-start3)/1000+"微秒");
long start4=System.nanoTime();
String s4=builder.toString();
long end4=System.nanoTime();
System.out.println("相同字符串單純StringBuilder.toString()耗時"+(end4-start4)/1000+"微秒");
}
}
運行了數十次,平均結果接近下邊結果:
相同字符串StringBuffer拼接並轉成string耗時5142微秒
相同字符串StringBuilder拼接並轉成string耗時3321微秒
相同字符串單純StringBuffer.toString()耗時13微秒
相同字符串單純StringBuilder.toString()耗時18微秒
讓我大跌眼鏡,果然是StringBuffer的toString方法效率略高一些,但不是2個類的性能瓶頸,2個類的主要性能差別還是差在同步與非同步上。
後來和前輩請教了一下,又讓我吃驚的是,前輩用JUnit測試的和我大相反,如下:
納了悶了,怎麼會這樣,後臺我讓前輩加上初始容量40000,結果還是與我的大相反:
不行,這是怎麼回事,得會前輩又給了我個截圖,如下:
前輩如果連續調用測試程序,我的原始測試程序才比較接近點前輩的。
倒騰了半天,又對這2個類有了重新的認識,StringBuffer的toSting方法稍好一些StringBuilder的,至於爲什麼,我也弄不明白這裏邊的道理。而非要比較StringBuffer和StringBuilder在線程安全的情況下相同的外界條件下到底哪個性能高哪個性能低,這個真不能一口咬死一口認定就是誰誰高,真要根據當時的項目進行測試,才能得出哪個性能高哪個性能低,進而抉擇選擇哪個工具更合適。
其實,項目中,如果字符串不是非常的大併發量不是非常的高,StringBuffer或者StringBuilder並不是項目中的性能瓶頸,真沒必要太糾結與選擇哪個的問題,在此前提下,爲了一個很好的編碼規範,建議大家確定線程安全的情況下選擇StingBuilder,線程不安全的情況下還是用StringBuffer,畢竟很多書中也都是這麼建議的。
轉載請註明—作者:Java我人生(陳磊興) 原文出處:http://blog.csdn.net/chenleixing/article/details/44087241