Core Java
Can synchronization be optimised away?
Overview
There is a common misconception that because the JIT is smart and synchronization can be eliminated for an object which is only local to a method that there is no performance impact.
A test comparing StringBuffer and StringBuilder
These two classes do basically the same thing except one is synchronized (StringBuffer) and the other is not. It is also a class which is often used in one method to build a String. The following test attempts to determine how much difference using one other the other can make.
static String dontOptimiseAway = null;
static String[] words = new String[100000];
public static void main(String... args) {
for (int i = 0; i < words.length; i++)
words[i] = Integer.toString(i);
for (int i = 0; i < 10; i++) {
dontOptimiseAway = testStringBuffer();
dontOptimiseAway = testStringBuilder();
}
}
private static String testStringBuffer() {
long start = System.nanoTime();
StringBuffer sb = new StringBuffer();
for (String word : words) {
sb.append(word).append(',');
}
String s = sb.substring(0, sb.length() - 1);
long time = System.nanoTime() - start;
System.out.printf("StringBuffer: took %d ns per word%n", time / words.length);
return s;
}
private static String testStringBuilder() {
long start = System.nanoTime();
StringBuilder sb = new StringBuilder();
for (String word : words) {
sb.append(word).append(',');
}
String s = sb.substring(0, sb.length() - 1);
long time = System.nanoTime() - start;
System.out.printf("StringBuilder: took %d ns per word%n", time / words.length);
return s;
}at the end prints with -XX:+DoEscapeAnalysis using Java 7 update 10
StringBuffer: took 69 ns per word StringBuilder: took 32 ns per word StringBuffer: took 88 ns per word StringBuilder: took 26 ns per word StringBuffer: took 62 ns per word StringBuilder: took 25 ns per word
Testing with one million words doesn’t change the results significantly.
Conclusion
- While the cost of using synchronization is small, it is measurable and if you can use StringBuilder it is preferred as it states in the Javadocs for this class.
- In theory, synchronization can be optimised away, but it is yet to be the case even in simple cases.
Reference: Can synchronization be optimised away? from our JCG partner Peter Lawrey at the Vanilla Java blog.


Micro-benchmarking is hard. Your numbers are not reflecting the results of the full-optimization of the JIT. If you run the tests 10000 times instead of 10 times the numbers change! On my computer: Initially: StringBuffer: took 67 ns per word StringBuilder: took 18 ns per word StringBuffer: took 64 ns per word StringBuilder: took 19 ns per word … but the on run 10000: StringBuffer: took 42 ns per word StringBuilder: took 28 ns per word StringBuffer: took 39 ns per word StringBuilder: took 29 ns per word The gap is much smaller. To get more consistent numbers, use a… Read more »
Well, I’d still use the faster class anyway. It’s good to know that if my method is run very often it will get faster, but if it does not run that often I want those extra milliseconds to do something else :-)
I wonder why synchronization was added in Java at the class level. When you are writing a class, you don’t know if it’s going to be used in local variables or in a static shared variable, so how can you decide about synchronization?