When to Use StringBuffer in Java

You will often see online that the difference between StringBuilder and StringBuffer is that StringBuffer is thread-safe and StringBuilder is not. But what does that mean and when exactly do you need a synchronized StringBuilder

Borislav Stoilov
2 min readJul 15, 2022
People/chars waiting in the buffer to be flushed

StringBuilders exist so we can efficiently concatenate strings. This is needed because strings in Java are immutable and every time we update a string a new one is created, this can lead to excessive RAM usage.

Since Java 7 string concatenation is replaced with string builders during compile time and there is only one case where we need builders. That is when we concat strings in a loop. In that case, the compiler fails to optimize the code during compilation and we end up creating a lot of strings.

But what if we want multiple threads to append to the StringBuilder?

If this code worked correctly we would expect nothing to be printed at line 14. However, we see a large log looking like this

That’s odd! That is the same string. Why then equals at line 13 misses it. Upon closer inspection, we notice that the strings are prefixed with null chars. Here is one of them

����������������������I just appended this!

This is because the StringBuilder works similarly to ArrayList. It maintains an internal char array and expands its size accordingly. When multiple threads try to expand the array at the same time, we observe this strange behavior. The null chars are the default value of char that the array is being initialized with.

This side effect is easy to reproduce, but there might be others, like chars being shuffled or invalid due to concurrent writes.

If we limit the thread pool to only one thread, the problem disappears and nothing is printed in the log. This shows that indeed the concurrency is causing this behavior

Now let’s fix this with StringBuffer

Same code, the only difference is that instead of using builder we use a buffer. We see nothing printed in the console this time. The program behaves correctly.

So why not use StringBuffer everywhere then?! Consider the following code

We add the same string the same number of times first in the buffer and then in the builder. On my machine, I get

Builder/Buffer 0.5617047942417436

which means StringBuilder is nearly twice as fast (this will vary from machine to machine so keep that in mind). This is because synchronization is one of the most expensive operations in Java and ideally it should be avoided as much as possible.

Only use StringBuffer if you plan to share it between threads, otherwise, StringBuilder will work just fine.

That will be all for this topic, let me know if I missed something, and thanks for reading.

--

--