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.

Related Whitepaper:

Java Essential Training

Author David Gassner explores Java SE (Standard Edition), the language used to build mobile apps for Android devices, enterprise server applications, and more!

The course demonstrates how to install both Java and the Eclipse IDE and dives into the particulars of programming. The course also explains the fundamentals of Java, from creating simple variables, assigning values, and declaring methods to working with strings, arrays, and subclasses; reading and writing to text files; and implementing object oriented programming concepts. Exercise files are included with the course.

Get it Now!  

3 Responses to "Can synchronization be optimised away?"

  1. Micha Riser says:

    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 micro-benchmarking framework which adapts the run count automatically and filters out values from unoptimized runs. As an example I use JBenchX (http://iquadrat.github.com/jbenchx):

    import org.jbenchx.annotations.Bench;

    public class SynchronizedBench {
    private final String[] words = new String[100000];
    public SynchronizedBench() {
    for (int i = 0; i < words.length; i++) {
    words[i] = Integer.toString(i);
    }
    }
    @Bench(divisor = 100000)
    public String testStringBuffer() {
    StringBuffer sb = new StringBuffer();
    for (String word : words) {
    sb.append(word).append(',');
    }
    return sb.substring(0, sb.length() – 1);
    }
    @Bench(divisor = 100000)
    public String testStringBuilder() {
    StringBuilder sb = new StringBuilder();
    for (String word : words) {
    sb.append(word).append(',');
    }
    return sb.substring(0, sb.length() – 1);
    }
    }

    which gives the numbers:
    [0] SynchronizedBench.testStringBuffer****.*.*..*…* 26.2ns
    [1] SynchronizedBench.testStringBuilder.****.**** 22.1ns

    which is really close to each other

    • ikk says:

      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 :-)

  2. ikk says:

    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?

Leave a Reply


seven − = 3



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.

Sign up for our Newsletter

20,709 insiders are already enjoying weekly updates and complimentary whitepapers! Join them now to gain exclusive access to the latest news in the Java world, as well as insights about Android, Scala, Groovy and other related technologies.

As an extra bonus, by joining you will get our brand new e-books, published by Java Code Geeks and their JCG partners for your reading pleasure! Enter your info and stay on top of things,

  • Fresh trends
  • Cases and examples
  • Research and insights
  • Two complimentary e-books