The Double Checked Locking confusion

8

Last Monday I was attending a presentation of Brian Goetz about the Java Memory Model. One of his points was about lazy initialization which concluded with "don’t use the Double Checked Locking idiom". Last Thursdays keynote at Devoxx Joshua Bloch tells the audience that if you really, really need performance you should use the the double checked locking idiom.

I was a little puzzled at first but after some reading it makes more sense. And they were both right!

Initialization of a variable can be very expensive because we need to go to a database or some expensive computation is behind it. Only in this case lazy initialization should be considered. Otherwise use ‘normal’ initialization.

[sourcecode language='java'] public class Bar {
private final Foo instance = new Foo();
}
[/sourcecode]

In this case there aren’t any possible concurrency problems. The thread-safety is guaranteed by the class loader. But if the initialization of the Foo instance is very expensive lazy initialization could be considered. If the instance variable is static the initialize-on-demand holder idiom can be used.

[sourcecode language='java'] public class Bar {
private static class LazyFooHolder {
public static final Foo instance = new Foo();
}
public static Foo getInstance() {
return LazyFooHolder.instance;
}
}
[/sourcecode]

In this case the initialization of the variable is done as soon as the static class LazyFooHolder gets loaded and the class-loader make sure we don’t have any concurrency problems. The LazyFooHolder class is loaded as soon it is referenced which will only happen when the getInstance method is called.

But what if lazy initialization is needed and the instance variable is not static. If we use the following example and are in a multi-thread environment it could happen that the expensive initialization is performed more than once. Which we try to avoid.

[sourcecode language='java'] public class Bar {
private Foo instance;
public Foo getInstance() {
if (instance == null) {
instance = new Foo();
}
return instance;
}
}
[/sourcecode]

Because the check and the initialization don’t happen as an atomic action we have the so called check-then-act problem. To solve this problem the synchronized keyword can be used on the method getInstance. By making the getInstance method synchronized a thread can only enter the method if it has a lock on the Foo instance.

[sourcecode language='java'] public class Bar {
private Foo instance;
public synchronized Foo getInstance() {
if (instance == null) {
instance = new Foo();
}
return instance;
}
}
[/sourcecode]

This should be the prefered solution for lazy initialization of a non static instance variable.

Because synchronization is a relative expensive operation some people came up with the double checked locking idiom. First check if the instance is created without a lock. If the instance is null then create a lock and check again if the instance is still null. If it is, create the instance and release the lock.

don’t use!!!
[sourcecode language='java'] public class Bar {
private Foo instance;
public Foo getInstance() {
if (instance == null) {
synchronized (this) {
if (instance == null) {
instance = new Foo();
}
}
}
return instance;
}
}
[/sourcecode] don’t use!!!

Because it is not guaranteed that the Foo instance is fully initialized before the reference to the instance variable is written you could end up with a partially constructed Foo.
It took a while before it was proven this idiom is broken but it is so don’t use it. This is exactly what Brian Goetz was telling.

Joshua Bloch said exactly the same thing about lazy initialization. Just use the synchronized keyword if you want to lazy initialize a instance variable. But if performance really, really matters, you can use the fixed version of the double checked locking idiom. For this you need to use the new JMM (Java 5) which gives some more guarantees about synchronization. The trick is to make the instance variable volatile. The volatile rule: A write to a volatile variable happens-before every subsequent read of that same volatile.

[sourcecode language='java'] public class Bar {
private volatile Foo instance;
public Foo getInstance() {
Foo result = instance;
if (result == null) {
synchronized (this) {
result = instance;
if (result == null) {
instance = result = new Foo();
}
}
}
return result;
}
}
[/sourcecode] In this example an extra local variable result is used which seems not necessary. And strictly it isn’t but Joshua claims that the use of the local variable gains a 25% performance gain on his machine. The reason for this lies within the optimizations the compiler applies. Apparently the generated byte code runs faster on the JVM.

Because it is easy to misunderstand the code of Joshua or even forget the volatile keyword on the instance I agree with Brian not to use the double-checked-locking. But there are some use cases that need the best performance one can get. In this I would use the fixed version of the idiom but with care and some good comments in the code.

To conclude:

* Only use lazy initialization when really needed, otherwise use ‘normal’ initialization
* When the instance is static use the initialize-on-demand holder idiom
* Use a synchronized method if the instance variable is non static
* When performance is really important use the fixed double checked locking with a volatile variable and some comments in the code. For best performance copy the example of Joshua.

Some references:

* http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
* http://jeremymanson.blogspot.com/
* http://www.javaworld.com/jw-02-2001/jw-0209-double.html
* http://www.briangoetz.com/pubs.html

Share.

About Author

8 Comments

  1. Why the result variable is needed there?
    Why is it not enough to add the volatile keyword?
    when doing if (instance == null ) – read operation is performed.

    Thanks

  2. @Emiel, Your right the synchronise will not only create a monitor but it will also create memory bariers. But the problem here is the first check for null on the instance variable. This check is outside the synchronized block. So whithout the volatile there are no guarantees that it thread A sees the same as thread B that just created the instance. By using the volatile the second thread also need to update its memory. For a better explanation read http://www.javaworld.com/jw-02-2001/jw-0209-double.html?page=1

  3. @Jean-Francois, Peter: You are both right. They were static before but then I thought maybe is better to avoid having this singleton thing and don’t be confusioning with more static keywords. But I forgot to rename my class Foo to Bar. Then again this looks a bit weird but I tried to get the focus on the real issue here.
    I will fix this soon. Thanks for your comments.

  4. Hi, I think you have forgotten “static” for examples 3, 4, 5 and 6 above. Both “instance” and “getInstance()” should be static else your code is impossible to execute (considering that Foo constructor is private which is a must for a singleton.

    It is a pity to take the poor old singleton pattern (which is bad, I hope everybody is convinced of this) as an example for the double checked locking pattern. There are better examples (that make sense in the real world) than the singleton that anyway is a bad example by itself.

  5. You have forgotten a few statics:

    public class Foo {
    private final Foo instance = new Foo();
    }

    should be

    public class Foo {
    private static final Foo instance = new Foo();
    }

    The first example leads to a stackoverflow :)

    But nice blogpost. Concurrency is a very hard topic to get right, and to be honest I’m really questioning the approach Java (and other normal oo languages) are taking. Perhaps Software Transactional Memory could mean to modern languages like garbage collection meant to java.

  6. In your singleton-like example, the best is to use class-loader synchronization. I’m glad this is finally becoming popular, because so few people I’ve worked with would believe me until Josh started recommending it. Use either a static inner class to hold the parent’s instance or, if you prefer the newest style, use the enum trick.

    For normal lazy initialization, the simplest approach (which is also quite efficent) is to use a FutureTask. I’m not sure why this isn’t popular, perhaps it doesn’t look magical enough to have the same coolness factor. Regardless, simply wrap the initialization logic in a Callable, create a FutureTask with it, and execute run() before the get() call. The first thread to call run() will change the task’s state and execute, while the rest will no-op. You can reuse this logic via a simple utility – mine is called a “LazyFuture”. The resulting code is fast, simple, and provides the desired behavior in a less error-prone manner. You also won’t run into bad practices, such as synchronizing on “this”, because the library does it cleanly for you. The only downside is that you don’t get to act like such a hot-shot since the code isn’t complex enough to brag about. ;)