Running on Java 24-ea+24-2960 (Preview)
Home of The JavaSpecialists' Newsletter

061Double-Checked Locking

Author: Dr. Heinz M. KabutzDate: 2002-12-07Java Version: 1.4Category: Performance
 

Abstract: The Singleton pattern allows for a single instance to be shared throughout the program. The question we will answer is how to initialize this.

 

Welcome to the 61st edition of The Java(tm) Specialists' Newsletter sent to 5261 Java Specialists in 91 countries. Since my last newsletter I had the fortune of celebrating yet another birthday - try guess how old I am ;-)

Has your application ever caused an OutOfMemoryError? Would you like to know how you can receive a warning before that actually happens? Have a look at Issue 092.

javaspecialists.teachable.com: Please visit our new self-study course catalog to see how you can upskill your Java knowledge.

Double-Checked Locking *yawn*

No newsletter writer can claim that he is successful if he has not written at least once about double-checked locking and how it is theoretically broken. It is the ideal topic to write about. When you read my theoretical proofs, you will think I am very clever, thus enabling me to raise my rates next time you ask for help ;-) At the same time, reproducing these problems is extremely difficult, so it is unlikely that you can even contradict me.

Let's take the Singleton pattern, described in the my Design Patterns Course . If a Singleton does not need to be extendible, I write it like this:

public class Singleton {
  private static final Singleton instance = new Singleton();
  public static Singleton getInstance() { return instance; }
  private Singleton() {}
  // other methods that you would need to do the actual work
}

The class will be loaded when it is needed at which point the instance field is created.

Another way of writing the Singleton is:

public class Singleton {
  private static Singleton instance;
  public static synchronized Singleton getInstance() {
    if (instance == null) {
      instance = new Singleton();
    }
    return instance;
  }
  private Singleton() {}
  // other methods that you would need to do the actual work
}

The advantage of that approach is that the Singleton instance is only created when you first use it. However, the class loader would take care of that aspect anyway, so we do not win anything by complicating our lives like this. It does not win us anything, but at least it works.

The problem with the new Singleton is that every time you call getInstance(), you will have to synchronize, even though you only really should need to the first time. Clever people have thus come up with this pattern:

public class Singleton {
  private static Singleton instance;
  public static Singleton getInstance() {
    if (instance == null) {
      synchronized(Singleton.class) {
        if (instance == null) {
          instance = new Singleton();
        }
      }
    }
    return instance;
  }
  private Singleton() {}
  // other methods that you would need to do the actual work
}

That mechanism is commonly called "Double-Checked Locking" or DCL for short. It is broken, at least in theory. In theory what may happen is that due to byte reordering, before the first thread has finished setting up the Singleton, i.e. has finished calling the constructor of the Singleton, the second thread already has a handle to it. In theory, therefore, it is possible that a thread can get a handle to a half-baked object using this mechanism.

I have tried to gather some evidence that with the current JVM implementations the problem can occur. I have written test code and executed it on a friend's multi-processor. I was not successful in proving my assertions. I have spoken to a number of authors who have written about this problem, and they also do not have firm evidence that this occurs in the real world. I therefore offer no proof or even claim that what I wrote about in this newsletter is true.

That is really all I have to say about the matter. Avoid the double-checked locking to avoid synchronization. In JDK 5 they are tidying up the memory model thus showing more clearly that DCL is broken. It can be written correctly by making the instance field volatile. In the meantime, try not to be too clever ;-)

Here is a challenge: I have not found a Singleton that is extendable in such a way that at compile time it is checked that there is only ever one instance. During my Design Patterns Course, I usually spend quite a bit of time on the Singleton, discussing things like why it is a pattern to avoid, what the differences between a Singleton and class methods are, etc. One of the issues we spend some time thinking about is the whole issue of making the Singleton extendable - I call it a polymorphic Singleton.

That's it for this week.

Heinz

 

Comments

We are always happy to receive comments from our readers. Feel free to send me a comment via email or discuss the newsletter in our JavaSpecialists Slack Channel (Get an invite here)

When you load these comments, you'll be connected to Disqus. Privacy Statement.

Related Articles

Browse the Newsletter Archive

About the Author

Heinz Kabutz Java Conference Speaker

Java Champion, author of the Javaspecialists Newsletter, conference speaking regular... About Heinz

Superpack '23

Superpack '23 Our entire Java Specialists Training in one huge bundle more...

Free Java Book

Dynamic Proxies in Java Book
Java Training

We deliver relevant courses, by top Java developers to produce more resourceful and efficient programmers within their organisations.

Java Consulting

We can help make your Java application run faster and trouble-shoot concurrency and performance bugs...