String performance test

I found string plus using StringBuffer but not StringBuilder when I was implementing my simple JVM. So I wrote some test case to test it. But it became using StringBuilder but not StringBuffer. So I guess whether use StringBuffer or StringBuilder is depend on compiler option. Any way I got a performance test result between using StringBuffer and StringBuilder. The result is that using StringBuilder is much faster than using StringBuffer . The time consume ratio between using StringBuilder and StringBuffer is about 2:3 .

 

Here comes my test code.

 

public class StringAddTest implements Runnable {

    static long time1 = 0;
    static long time2 = 0;
    static long time3 = 0;

    /**
     * @param args
     * @throws InterruptedException
     */
    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(new StringAddTest());
        Thread thread2 = new Thread(new StringAddTest());
        Thread thread3 = new Thread(new StringAddTest());
        Thread thread4 = new Thread(new StringAddTest());
        thread1.start();
        thread2.start();
        thread3.start();
        thread4.start();

        thread1.join();
        thread2.join();
        thread3.join();
        thread4.join();

        System.out.println("stringAdd1 spent " + time1 + " ms");
        System.out.println("stringAdd2 spent " + time2 + " ms");
        System.out.println("stringAdd3 spent " + time3 + " ms");
    }

    public static void stringAdd1(int n) {
        long start = System.currentTimeMillis();
        for (int i = 0; i < n; i++) {
            String a = "First";
            String b = "Second";
            String x = a + b + i;
        }
        long spent = System.currentTimeMillis() - start;
        time1 += spent;
        System.out.println("TestStringAdd1 spent " + spent + "ms");
    }

    public static void stringAdd2(int n) {
        long start = System.currentTimeMillis();
        for (int i = 0; i < n; i++) {
            String a = "First";
            String b = "Second";
            String x = new StringBuilder().append(a).append(b).append(i).toString();
        }
        long spent = System.currentTimeMillis() - start;
        time2 += spent;
        System.out.println("TestStringAdd2 spent " + spent + "ms");
    }

    public static void stringAdd3(int n) {
        long start = System.currentTimeMillis();
        for (int i = 0; i < n; i++) {
            String a = "First";
            String b = "Second";
            String x = new StringBuffer().append(a).append(b).append(i).toString();
        }
        long spent = System.currentTimeMillis() - start;
        time3 += spent;
        System.out.println("TestStringAdd3 spent " + spent + "ms");
    }
    
    public static void StringAddx()
    {
        String orignal = "Original";
        orignal += "What";
    }

    public void run() {
        int n = 1000 * 1000;
        for (int i = 0; i < 10; i++) {
            stringAdd1(n);
            stringAdd2(n);
            stringAdd3(n);
            
            stringAdd3(n);
            stringAdd2(n);
            stringAdd1(n);
            
            stringAdd2(n);
            stringAdd3(n);
            stringAdd1(n);
        }
    }
}

 I ran it for several times. The results are closed to each other. One test result on my machine is

DirectStringAdd      spent 138057 ms
StringBuilderAppend  spent 152647 ms
StringBufferAppend   spent 256578 ms
 

From the result can see that use direct string plus is a little faster than use StringBuilder. I was trying to figure it out by analyze the binary code generated and add two more test case. Here comes my new test code.

public class StringAddTest implements Runnable {

    static long timeDirectStringAdd = 0;
    static long timeStringBuilderAppend = 0;
    static long timeStringBufferAppend = 0;
    static long timeStringBuilderAppend2 = 0;
    static long timeStringBufferAppend2 = 0;
    
    /**
     * @param args
     * @throws InterruptedException
     */
    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(new StringAddTest());
        Thread thread2 = new Thread(new StringAddTest());
        Thread thread3 = new Thread(new StringAddTest());
        Thread thread4 = new Thread(new StringAddTest());
        thread1.start();
        thread2.start();
        thread3.start();
        thread4.start();

        thread1.join();
        thread2.join();
        thread3.join();
        thread4.join();

        System.out.println("DirectStringAdd      spent " + timeDirectStringAdd + " ms");
        System.out.println("StringBuilderAppend  spent " + timeStringBuilderAppend + " ms");
        System.out.println("StringBufferAppend   spent " + timeStringBufferAppend + " ms");
        System.out.println("StringBuilderAppend2 spent " + timeStringBuilderAppend2 + " ms");
        System.out.println("StringBufferAppend2  spent " + timeStringBufferAppend2 + " ms");
    }

    public static void directStringAdd(int n) {
        long start = System.currentTimeMillis();
        for (int i = 0; i < n; i++) {
            String a = "First";
            String b = "Second";
            String x = a + b + i;
        }
        long spent = System.currentTimeMillis() - start;
        timeDirectStringAdd += spent;
        System.out.println("DirectStringAdd      spent " + spent + "ms");
    }

    public static void stringBuilderAppend(int n) {
        long start = System.currentTimeMillis();
        for (int i = 0; i < n; i++) {
            String a = "First";
            String b = "Second";
            String x = new StringBuilder().append(a).append(b).append(i).toString();
        }
        long spent = System.currentTimeMillis() - start;
        timeStringBuilderAppend += spent;
        System.out.println("StringBufferAppend   spent " + spent + "ms");
    }

    public static void stringBuilderAppend2(int n) {
        long start = System.currentTimeMillis();
        for (int i = 0; i < n; i++) {
            String a = "First";
            String b = "Second";
            String x = new StringBuilder(a).append(b).append(i).toString();
        }
        long spent = System.currentTimeMillis() - start;
        timeStringBuilderAppend2 += spent;
        System.out.println("StringBufferAppend2  spent " + spent + "ms");
    }
    
    public static void stringBufferAppend(int n) {
        long start = System.currentTimeMillis();
        for (int i = 0; i < n; i++) {
            String a = "First";
            String b = "Second";
            String x = new StringBuffer().append(a).append(b).append(i).toString();
        }
        long spent = System.currentTimeMillis() - start;
        timeStringBufferAppend += spent;
        System.out.println("StringBuilderAppend  spent " + spent + "ms");
    }
    
    public static void stringBufferAppend2(int n) {
        long start = System.currentTimeMillis();
        for (int i = 0; i < n; i++) {
            String a = "First";
            String b = "Second";
            String x = new StringBuffer(a).append(b).append(i).toString();
        }
        long spent = System.currentTimeMillis() - start;
        timeStringBufferAppend2 += spent;
        System.out.println("StringBuilderAppend2 spent " + spent + "ms");
    }
    
    
    public static void StringAddx()
    {
        String orignal = "Original";
        orignal += "What";
    }

    public void run() {
        int n = 1000 * 1000;
        for (int i = 0; i < 5; i++) {
            directStringAdd(n);
            stringBuilderAppend(n);
            stringBuilderAppend2(n);
            stringBufferAppend2(n);
            stringBufferAppend(n);
            
            stringBufferAppend(n);
            stringBufferAppend2(n);
            stringBuilderAppend2(n);
            stringBuilderAppend(n);
            directStringAdd(n);
            
            stringBuilderAppend(n);
            stringBuilderAppend2(n);
            stringBufferAppend2(n);
            stringBufferAppend(n);
            directStringAdd(n);
        }
    }
}
 

And the test result is like

DirectStringAdd      spent 67991 ms
StringBuilderAppend  spent 76464 ms
StringBufferAppend   spent 120135 ms
StringBuilderAppend2 spent 65543 ms
StringBufferAppend2  spent 118215 ms

 I picked up the binary code snippet from the test case and list it in following table.

1:
String x = a + b + i; 
    17  new java.lang.StringBuilder [56]
    20  dup
    21  aload 4 [a]
    23  invokestatic java.lang.String.valueOf(java.lang.Object) : java.lang.String [106]
    26  invokespecial java.lang.StringBuilder(java.lang.String) [60]

2:
String x = new StringBuilder().append(a).append(b).append(i).toString();
    17  new java.lang.StringBuilder [56]
    20  dup
    21  invokespecial java.lang.StringBuilder() [125]
    24  aload 4 [a]
    26  invokevirtual java.lang.StringBuilder.append(java.lang.String) : java.lang.StringBuilder [69]
 
3:
String x = new StringBuilder(a).append(b).append(i).toString();
    17  new java.lang.StringBuilder [56]
    20  dup
    21  aload 4 [a]
    23  invokespecial java.lang.StringBuilder(java.lang.String) [60]

1: String.valueOf(String) only cost a little. It only need return the reference.

2: append need a string copy. It cost quite much.

3: it even don't need valueOf. So it is the fastest.

 

你可能感兴趣的:(jvm,thread,UP,performance)