Why a synchronized StringBuffer was never a good idea
Introduction
StringBuffer is a synchronized class for mutable strings. The main problem with making it synchronized is that- It was usually used as a local variable so making it synchronized just made it slower.
- It was never a good idea to use it in a multi-threaded way. This problem is that developers assumed that methods which used StringBuffer were themselves thread safe when they were not.
The problem with StringBuffer
This is an example from a real class which is used in production in many trading systems. It's not a commonly used but you might assume that StringBuffer gives you thread safety, when it doesn't.private StringBuffer sb = new StringBuffer(); public void addProperty(String name, String value) { if (value != null && value.length() > 0) { if (sb.length() > 0) { sb.append(','); } sb.append(name).append('=').append(value); } }While individual calls are thread safe, multiple calls are not. It is almost impossible to find a good use for StringBuffer that doesn't involve multiple calls (including toString)
A puzzle
Imagine three threads call (in no particular order)T1: addProperty("a", "b"); T2: addProperty("c", "d"); T3: sb.toString();write a program which will generate every possible output of T3's sb.toString() I found 89. With thread safety, you might reduce this to 4. Note: if you used StringBuilder it would be worse, but at least you might not assume your method is thread safe when it is not. e.g. SimpleDateFormat uses StringBuffer ;)
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)
Tags:
Comments
Vishal Jain replied on Thu, 2013/04/25 - 5:37am
You are right, I've also seen such code in production many times. I think every java developer should read Java concurrency in practice book compulsarily. I guess this wouldn't have happened if they knew the basics of concurrency. Thanks for the post.
Hector Adolfo Alonso replied on Thu, 2013/04/25 - 9:26pm
Hi Peter:
Good point !
a. - sb.append ("Hi") is synchronized with respect to sb. While some thread is executing this method, no other thread can execute another synchronized method on sb.
b. - If a thread runs sb.append("Good").append("morning").append("Peter"), while another runs sb.append("Good").append("night").append ("Peter"), six append ("...") invocations on sb will be synchronized on sb, but nothing guarantees that the first three were executed before or after the last three. You may obtain multiple combinations for sb content.c. - synchronized (sb) {sb.append("Good").append("morning").append("Peter!");} is synchronized with respect to sb. While some thread executes this synchronized block, no other thread can execute another method or synchronized block on sb.
d. - If a thread runs
synchronized (sb) {
sb.append("Good").append("morning").append("Peter");
}
while another runs
synchronized (sb) {
sb.append("Good").append("night").append("Peter");
}
both blocks are synchronized with respect to sb. You may ensure that you get only 2 possible contents for sb:
- "Good morning Peter! Good nigth Peter!"
or
- "Good night Peter! Good morning Peter!"
Javadoc for SimpleDateFormat states that date formats are not thread safe.
Héctor./
Peter Lawrey replied on Fri, 2013/04/26 - 2:54am
in response to:
Hector Adolfo Alonso
If you are forced to synchronized your accesses to an object externally, it is simpler and clearer IMHO to use an unsynchronized class. I have seen many examples of code which doesn't worry about synchronization because it is using a synchronized StringBuffer.
With biased locking, this can make race conditions even harder to detect.
Dan Howard replied on Fri, 2013/04/26 - 5:47am
Ever heard of StringBuilder? What is this 1997?
Peter Lawrey replied on Fri, 2013/04/26 - 10:06am
in response to:
Dan Howard
Java 5.0 came out in 2004.
Libraries still use StringBuffer, just in case there is some multi-threaded is using it even though it is quite likely it is not thread safe anyway.
BTW Java 7 update 21 src.zip
Occurances of "new StringBuffer": 571
Occurances of "new StringBuilder": 265
We a still a long way from the JDK mostly using StringBuilder. :]