StringBuffer vs StringBuilder

Filed Under: Java
StringBuffer Vs StringBuilder

StringBuffer vs StringBuilder is a popular interview question in core java interview. Let’s look into some important points when comparing StringBuilder vs StringBuffer.

StringBuffer vs StringBuilder

  1. StringBuffer is the thread safe utility class to perform several operations on Strings. It contains append() and insert() methods that are widely used to perform operations on Strings in a multi-thread environment. If you will check the source code, most of its functions are synchronized for thread safety.

    Since most of the String operations, for example, concatenation happens in a single thread environment, Java 1.5 introduced another utility class StringBuilder to perform similar operations but doesn’t provide thread safety. If you will look into its source code, all the methods are unsynchronized. This is the most important point for StringBuffer vs StringBuilder.

  2. StringBuffer has some extra methods such as substring, length, capacity, trimToSize etc. However, these are not required since you have all these present in String too. That’s why these methods were never implemented in StringBuilder class.
  3. StringBuffer was introduced in Java 1.0 whereas StringBuilder class was introduced in Java 1.5 after looking at shortcomings of StringBuffer.
  4. StringBuilder is faster than StringBuffer because of no synchronization.

When I started learning Java, the one thing I stick to my heart is to avoid synchronization as far as possible as it adds extra overhead to the system and slows down the processing.

StringBuilder vs StringBuffer Performance

Here, I am trying to check the effect on performance because of synchronization with a sample program that performs append() and insert() on StringBuffer and StringBuilder object for multiple times.


package com.journaldev.java;

import java.util.GregorianCalendar;

public class TestString {

	public static void main(String[] args) {
		System.gc();
		long start=new GregorianCalendar().getTimeInMillis();
		long startMemory=Runtime.getRuntime().freeMemory();
		StringBuffer sb = new StringBuffer();
		//StringBuilder sb = new StringBuilder();
		for(int i = 0; i<100000; i++){
			sb.append(":"+i);
			sb.insert(i, "Hi");
		}
		long end=new GregorianCalendar().getTimeInMillis();
		long endMemory=Runtime.getRuntime().freeMemory();
		System.out.println("Time Taken:"+(end-start));
		System.out.println("Memory used:"+(startMemory-endMemory));
	}
}

I changed the value of “i” in the above code from 1,000 to 1,00,000 and logged the time taken and memory used. I ran the same code for StringBuffer object also to check the time and memory values. I have executed the code 5 times for each case and then calculated the average values.

Java 1.5

Value of i StringBuffer (Time, Memory) StringBuilder (Time, Memory)
1,000 5, 0 5, 0
10,000 139, 2113992 142, 2113952
1,00,000 22725, 7496096 22447, 7496096

Java 1.6

Value of i StringBuffer (Time, Memory) StringBuilder (Time, Memory)
1,000 5, 0 5, 0
10,000 136, 2113992 140, 2113952
1,00,000 22722, 7496096 22532, 7496096

I have executed the code several times and didn’t see much difference in the execution time whether it’s StringBuffer or StringBuilder object.

Logically, StringBuilder should always perform well in case of the single-threaded environment but it’s not the case with 10,000 iterations.

If somebody can run the above code and check the timings to verify the result, it would be great. However, I am clueless about the result I am getting here.

Update (24 Dec 2010)

When I wrote the above program for StringBuffer and StringBuilder performance check, I assumed that String operation and JVM internal implementation for memory allocation will take almost the same time.

First of all thanks to Andy, JM Morel, and Hauke for the comments.

From the comments, I concluded that in my program most of the time is taken by insert() operation because it needs a lot of memory allocation and garbage collection because of the huge size of StringBu* object. So I have decided to remove insert() operation from my testing.

Also, sb.append(“:”).append(i); is better than sb.append(“:”+i);. It removes string concatenation and doubles the append operation.

This time I am testing my program for 10,00,000 and 1,00,00,000 iterations.

Updated TestString class code:


package com.journaldev.java;

import java.util.GregorianCalendar;

public class TestString {

	public static void main(String[] args) {
		System.gc();
		long start=new GregorianCalendar().getTimeInMillis();
		long startMemory=Runtime.getRuntime().freeMemory();
		StringBuffer sb = new StringBuffer();
		//StringBuilder sb = new StringBuilder();
		for(int i = 0; i<10000000; i++){
			sb.append(":").append(i);
		}
		long end=new GregorianCalendar().getTimeInMillis();
		long endMemory=Runtime.getRuntime().freeMemory();
		System.out.println("Time Taken:"+(end-start));
		System.out.println("Memory used:"+(startMemory-endMemory));
	}
}

Output of the above program is:

Java 1.5

Value of i StringBuffer (Time, Memory) StringBuilder (Time, Memory)
10,00,000 209, 32626200 134, 32626200
1,00,00,000 2319, 5768536 1590,5768536

Java 1.6

Value of i StringBuffer (Time, Memory) StringBuilder (Time, Memory)
10,00,000 206, 32626200 131, 32626200
1,00,00,000 2253, 5768536 1486, 5768536

Java 8

StringBuffer vs StringBuilder, StringBuilder vs StringBuffer

Value of i StringBuffer (Time, Memory) StringBuilder (Time, Memory)
10,00,000 808, 149356704 633, 149356704
1,00,00,000 7448, 147783888 6179, 147783888

Now it’s clear that StringBuilder performs better than StringBuffer even in the case of single-threaded environment and this difference in performance can be caused by synchronization. That’s all for StringBuffer vs StringBuilder.

You can check out more String related programs from our GitHub Repository.

References:

Comments

  1. Viktor Mikulasek says:

    Hello!
    Can you explain me why is so big difference in Java 8 agains Java 5 or 6?
    Thanks

  2. http://tinyurl.com/freewiley58140 says:

    I really Feel posting, “StringBuffer vs StringBuilder – Benchmarking |
    JournalDev” was in fact really good! I reallycan’t see eye to eye with you even more! Finally looks like I actuallyfound a blog really worth looking through. Thanks for your time, Lashonda

  3. incognito says:

    I don’t trust any benchmarks where the benchmarker writes “1,00,00,000” as a number. I’ve never seen such – lets call it creative – use of a *thousands* separator.

    1. bob says:

      That’s the digit grouping convention used in India. You, on the other hand, forgot to put an apostrophe in “lets”. Shame on you!

  4. Ron says:

    StringBuffer is so fast because of Biased Locking. If you re-run with -XX:-BiasedLocking, I bet it loses by much more.

  5. Hauke says:

    The VM is optimizing away the synchronisation, when it is not needed so StringBuilder and StringBuffer gbehave the same. The recommendation is old and outdated. Use StringBuffer when you need synchronisation, not StringBuilder for performance reasons.

    This line “sb.append(“:”+i);” is a bad idea, especially when playing around with string performance.

    1. Pankaj says:

      Yeah sb.append(“:”+i); is a bad idea but I assumed that string operations will take similar time for both of the objects. I will update my program and post the results again.

  6. JM Morel says:

    in your loop (line 14), you’re instantiating a new String on each iteration. This costs more than the append operation. Replace with sb.append(":").append(i); and you should see a difference. Moreover, I’ve already made same kind of tests, and the number of iteration must be much greater than 10 000 (let’s try 1000000) to see a significative difference with a so simple test.

    1. Pankaj says:

      Replaced and tested with higher values. Post is also updated with this and now goes well with my understanding now.

  7. Ricardo Veguilla says:

    I can’t find the reference right now, but, when Java 5 was released, I read that the JVM will automatically change StringBuffer instances to StringBuilder instances for single thread scenarios.

    1. Pankaj says:

      I have never heard this or read this anywhere…

      1. Tejas says:

        Pankaj Sir,

        I have read this
        ….

        Here itself for 1st and the last time , never-ever again

  8. Andy Till says:

    StringBuffer:
    Time Taken:11687
    Memory used:3578440

    StringBuilder:
    Time Taken:11625
    Memory used:3578440

    Not much difference??? I think the main test here is how much memory can the vm grab in 11 seconds. If you call sb.setLength(0) in the loop it will clear it so memory will not spend so much time allocating new char arrays and GCing the olds ones, make sure to use append instead of insert. This will make it complete in under 70ms on my machine.

    Its very difficult to tell but the vm could figure that since the StringBuffer is a local variable then there is no need to synchronize, or it could use lock coarsening to not synchronize individual method calls but on the whole loop or wider. Not sure how to check this though?

    1. Pankaj says:

      Good point made, I am removing insert operation in my test. Results are posted again…

Leave a Reply

Your email address will not be published. Required fields are marked *

close
Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages