SringBuilder vs StringBuffer revisited

As you already know, java's StringBuilder and StringBuffer are virtually the same and the only difference is that all methods on the Buffer are synchronized. And the conventional wisdom tells us that synchronization adds extra and unnecessary overhead. There are articles about how it is best to use Builder in the general case of the local string concatenation. Let's test it:

import org.openjdk.jmh.annotations.*;
import java.util.concurrent.TimeUnit;

@Warmup(iterations = 5, time = 10, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Fork(1)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@BenchmarkMode(Mode.AverageTime)
public class MyBenchmark {

    @Benchmark
    public String testBuilder() {
        StringBuilder b = new StringBuilder(1024);
        b.append("Hello");
        b.append(' ');
        b.append(3);
        b.append("am!");
        return b.toString();
    }

    @Benchmark
    public String testBuffer() {
        StringBuffer b = new StringBuffer(1024);
        b.append("Hello");
        b.append(' ');
        b.append(3);
        b.append("am!");
        return b.toString();
    }
}

And the result on JDK 1.7:

Benchmark                        Mode  Samples    Score    Error  Units
o.s.t.MyBenchmark.testBuffer     avgt        5  324.303 ± 94.488  ns/op
o.s.t.MyBenchmark.testBuilder    avgt        5  290.062 ± 96.538  ns/op

Looks like the Builder is faster, does not it? Hold on, take a look at the confidence interval. And why are we using 1.7, let's try JDK 1.8:

Benchmark                        Mode  Samples    Score    Error  Units
o.s.t.MyBenchmark.testBuffer     avgt        5  287.292 ± 49.302  ns/op
o.s.t.MyBenchmark.testBuilder    avgt        5  280.481 ± 41.504  ns/op

And, just for fun, JDK 1.9 (dev build):

Benchmark                        Mode  Samples    Score    Error  Units
o.s.t.MyBenchmark.testBuffer     avgt        5  273.393 ± 65.169  ns/op
o.s.t.MyBenchmark.testBuilder    avgt        5  269.278 ± 27.776  ns/op

Java has a JIT compiler that can eliminate extra synchronization from the bytecode. And the case when synchronization is on a local instance that never leaves the thread is one of the easiest. JIT was getting better and better as the time passed, and by now is a truly great piece of software.

Unless you are stuck on an old JVM, there is not much difference in StringBuilder and StringBuffer performance. At least if all you add to the builder is other strings, chars and integers. Curious why? Because OpenJDK has intrinsics for those methods only:

_StringBuffer_append_char
_StringBuffer_append_int
_StringBuffer_append_String

Of course that may change in the future.