字符串鏈接效率測試:stringbuilder》stringbuffer》+ 【轉:儘可能使用StringBuilder和StringBuffer進行字符串鏈接】

前幾天性能測試的時候發現一個web 端cpu出現驟降的問題,一直沒有找到緣由,起初懷疑是tomcat的線程數有關,後來有懷疑是跟數據庫的響應時間太長有關係,後來都一一排除了。 java

之因此此問題比較難以定位主要是由於經過現有的監控工具沒法獲知和分析tomcat內部各個線程的佔用資源的狀況。 web

上週裝了一下jprofiler,而後又從新進行了一次壓力測試,終於找到了問題的根源:) 數據庫

主要的資源消耗點是:字符串的拼接上。代碼中時使用」+「來進行字符串鏈接的。 tomcat

(ps:jprofiler監控的粒度很細,可是因爲其自己運行佔用的資源消耗量也很大,所以在進行性能測時不能用其做爲監控工具,在分析問題方面仍是蠻有用的;jconsole是java自帶的監控工具,其在遠程監控應用程序時,不會對程序的性能形成影響,但因爲其監控的粒度仍是有些粗,所以tomcat內部的資源佔用狀況仍是沒法進行分析的 安全

 

 

JAVA中String ,StringBuffer,SrtingBuilder三個對象鏈接字符串的效率。
比較下究竟誰的效率高。由於咱們常常都聽有經驗的人說,避免使用String經過「+」鏈接字符串,特
別是鏈接的次數不少的時候,必定要用StringBuffer,但究竟效率多高,速度多快,我也沒有測試過,
因此我就動手測試下,順便把測試結果跟你們一塊兒分享,但願你們共同討論此問題。
下邊是個人測試代碼,可直接運行:
app

 

public class TestStringConnection {
    
    //鏈接時間的設定
    private final static int n = 20000;
    
    public static void main(String[] args){
       TestStringConnection test = new TestStringConnection ();
       test.testStringTime(n);
       test.testStringBufferTime(n);
       test.testStringBuilderTime(n);
       
       
//       //鏈接10次
//       test.testStringTime(10);
//       test.testStringBufferTime(10);
//       test.testStringBuilderTime(10);
//       
//       //鏈接100
//       
//       test.testStringTime(100);
//       test.testStringBufferTime(100);
//       test.testStringBuilderTime(100);
//       
//       
//       
//       //鏈接1000
//       
//       test.testStringTime(1000);
//       test.testStringBufferTime(1000);
//       test.testStringBuilderTime(1000);
//       
//       
//      //鏈接5000
//       
//       test.testStringTime(5000);
//       test.testStringBufferTime(5000);
//       test.testStringBuilderTime(5000);
//       
//       
// //鏈接10000
//       
//       test.testStringTime(10000);
//       test.testStringBufferTime(10000);
//       test.testStringBuilderTime(10000);
//       
// //鏈接20000
//       
//       test.testStringTime(20000);
//       test.testStringBufferTime(20000);
//       test.testStringBuilderTime(20000);
    }
    
    /**
     *測試String鏈接字符串的時間
     */
    public void testStringTime(int n){
       long start = System.currentTimeMillis();
       String a = "";
       for(int k=0;k<n;k++ ){
           a += "_" + k;
       }
       long end = System.currentTimeMillis();
       long time = end - start;
       System.out.println("//////////////////////鏈接"+n+"次" );
       System.out.println("String time "+n +":"+ time);
       //System.out.println("String str:" + str);
    }
    
    /**
     *測試StringBuffer鏈接字符串的時間
     */
    public void testStringBufferTime(int n){
       long start = System.currentTimeMillis();
       StringBuffer b = new StringBuffer() ;
       for(int k=0;k<n;k++ ){
           b.append( "_" + k );
       }
       long end = System.currentTimeMillis();
       long time = end - start;
       System.out.println("StringBuffer time "+n +":"+ time);
       //System.out.println("StringBuffer str:" + str);
    }
    
    /**
     *測試StringBuilder鏈接字符串的時間
     */
    public void testStringBuilderTime(int n){
       long start = System.currentTimeMillis();
       StringBuilder c = new StringBuilder() ;
       for(int k=0;k<n;k++ ){
           c.append( "_" + k );
       }
       long end = System.currentTimeMillis();
       long time = end - start;
       System.out.println("StringBuilder time " +n +":"+ time);
       
       System.out.println("//////////////////////");
       //System.out.println("StringBuffer str:" + str);
    }

}
 

 

分別測試了n=10,100,500,1000,5000,10000,20000的時候,三個對象鏈接字符串所花費的時間,
作了個簡單統計,獲得以下數據:

 

測試環境:eclipse

由上邊的圖表結果對比,能夠清楚的看出,爲何你們都鼓勵用StringBuffer鏈接字符串了。在鏈接次數少
的狀況下,String的低效率表現並非很突出,可是一旦鏈接次數多的時候,性能影響是很大的,String進
行2萬次字符串的鏈接,大約須要1分鐘時間,而StringBuffer只須要94毫秒,相差接近500倍以上。而
StringBuffer和StringBuilder差異並不大,StringBuilder比StringBuffer稍微快點,我想是由於StringBuffer
是線程序安全的,StringBuilder不是線程序安全的,因此StringBuffer稍微慢點。

可是爲何String如此慢呢,分下以下簡單片斷 String result="";
result+="ok"; 這段代碼看上去好像沒有什麼問題,可是須要指出的是其性能很低,緣由是java中的String 類不可變的(immutable),這段代碼實際的工做過程會是如何的呢?經過使用javap工具我 們能夠知道其實上面的代碼在編譯成字節碼的時候等同的源代碼是: String result="";

StringBuffer temp=new StringBuffer();
temp.append(result);
temp.append("ok");
result=temp.toString();
短短的兩個語句怎麼呢變成這麼多呢?問題的緣由就在String類的不可變性上,而java程序爲了方便簡單的
字符串使用方式對+操做符進行了重載,而這個重載的處理可能所以誤導不少對java中String的使用。
因此,若是你對字符串中的內容常常進行操做,特別是內容要修改時,那麼使用StringBuffer,若是最後 須要String,那麼使用StringBuffer的toString()方法好了。可是 StringBuilder 的實例用於多個線程是不安 全的。若是須要這樣的同步,則建議使用 StringBuffer,由於StringBuffer是線程安全的。在大多數非多 線程的開發中,爲了提升效率,能夠採用StringBuilder代替StringBuffer,速度更快。
相關文章
相關標籤/搜索