Double Checked Locking in Java and Why it was broken before JDK 5?

Double checked locking pattern is one of the interesting topics on Java Interviews. Earlier, it was asked to see if Java developer can write code using a synchronized block or not, and now it asks to gauge the candidate's understanding of concurrency, volatile, and synchronization in Java. One of the simplest ways to write thread-safe Singleton was to make the getInstance() method synchronized but prior to JDK 1.6, a simple uncontented synchronization block was expensive, and that lead many developers to write the getInstance() method of Singleton class using double-checked locking idiom. This was one of the clever idioms of that time which only uses synchronization when the Singleton object is created as seen in the following code and thus improves the performance of the getInstance() method, which is used to retrieve the Singleton object.

In this article, we will learn quite many things about Double-checked locking pattern e.g. how to code it, how it work, benefits and shortcomings of this pattern, etc. But, let's first see the code.

And, If you are serious about learning design patterns and principles, I suggest you take a look at the Design Patterns in Java course on Udemy. This course covers both SOLID design principles like Open Closed and Liskov substitution, and all-important Object Oriented design patterns like Decorator, Observer, Chain of Responsibility, and much more


Here is one example of a thread-safe Singleton class in Java using double-checked locking pattern:

class DCLSingleton {

    private static volatile DCLSingleton _instance  = null;

    private DCLSingleton() {
    }

    public static DCLSingleton instance() {
        if (_instance == null) { // 1st check

            synchronized (DCLSingleton.class) {

                if (_instance == null) // 2nd check
                {
                    _instance = new DCLSingleton();
                }
            }
        }
        return _instance;
    }
}

There are a couple of important points to note about this code:

1) A static volatile field is used to hold the instance of the Singelton class. The volatile variable is key here, without volatile, it won't be thread-safe as explained in Java Concurrency in Practice as well.

Double checked locking in Singleton Java


2) The constructor is made private to disable instance creation outside of this class, but you can create an instance inside the class and that's what your getInstance() method does.

3) There are two checks to see if the _instance member variable is initialized or not and that's why this code idiom it's called double-checked locking idiom.

4) The first check is non-synchronized, which may see a partially constructed object because of instruction re-ordering by the compiler or JVM.

5) The second check is inside the synchronized block and only executes one time during lifespan of Singleton. That's why you get the performance boost becuase locking only happens one time during the lifespan of Singleton instance.




Why Double-checked locking is broken Prior to 5

The sole purpose of Double-checked locking was to avoid excessive synchronization and hence it relies on non-synchronized access of _instance field at the 1st check point. This appears harmless, but it is not.

Suppose one thread, Thread-1 is inside the synchronized block and it's creating Singleton instance and assigning a reference to _instance variable. In the meantime, the Thread scheduler stops the Thread-1. Now, a second thread, Thread-2 enters and come to 1st check point which is not synchronized, now there is a possibility that it can see half-initialized _instnace field and return that to the client, leading to subtle bugs in your program.

This issue was fixed by introducing the happens-before guarantee provided by the volatile variable in Java 1.5. According to this rule, write to a volatile field will happen before any read, which negates the possibility of seeing half initialized instance of Singleton class.

See Applying Concurrency and Multi-threading to Common Java Patterns for more details on happens-before guarantee.




Safe alternatives of Double-checked Locking Pattern

If getInstance() method is not bottleneck than the simplest way to avoid Double-checked locking is make the whole method synchronized. Java has come a long way in performance and penalty to synchronizing is a lot lesser than what it used to be.

Other alternative includes using Enum as Singleton in Java. Enum guarantees lot of features required by Singleton pattern out-of-the-box e.g. initialization to Enum constants are thread-safe, Enum also provides Serialization guarantee that only one instance of Singleton will exits and it's very easy to code as seen below:

public enum ThreadSafeSingleton{
  INSTANCE;
}

Another safe way to create thread-safe Singleton is using eager initialization which initializes Singleton instance at the time Singleton class is loaded into memory as opposed to when client class the getInstance() method. If your Singleton is not very heavy than this idiom works quite well.

class EagerSingleton {
   public static EagerSingleton singleton = new EagerSingleton ();
}


One more alternative of double checked locking is Initialization on Demand Holder idiom, which uses an inner class to encapsulate Singleton instance. This idiom takes advantage of the fact that Inner class is not loaded until they are referenced.

You can still use double checked locking pattern to create thread-safe Singleton classes in Java, but when you use double checked locking, don't forget to include the volatile modifer on Singleton instance.

Here is a bad and good example of double checkecd locking with Singleton in Java, following code misses the volatile modifier, hence Singleton is not thread-safe:

Double checked locking without volatile variable

You need to use the volatile variable to make the above code thread-safe in Java 1.5 as shown below:

Double checked locking in Java with volatile variable


That's all about why double checked locking was broken, why you should avoid it and what are some safe alternatives of double-checked locking for creating thread-safe Singleton in Java. Remember, you can use Double checked locking with Java 6, 7 or 8 but don't forget to make the _instance static variable as volatile, without that your Singleton will still be broken.


Further Learning
Design Pattern Library
From 0 to 1: Design Patterns - 24 That Matter - In Java 
Java Design Patterns - The Complete Masterclass
SOLID Principles of Object-Oriented Design


Other Java Design Patterns tutorials you may like
  • Top 5 Courses to learn Design Pattern in Java (courses)
  • 5 Free Courses to learn Object Oriented Programming (courses)
  • Difference between Factory and Dependency Injection Pattern? (answer)
  • Top 5 Courses to learn Microservices in Java with Spring (courses)
  • How to create thread-safe Singleton in Java? (example)
  • How to implement the Strategy Design Pattern in Java? (example)
  • Difference between Factory and AbstractFactory Pattern? (example)
  • 18 Java Design Pattern Interview Questions with Answers (list)
  • How to design a Vending Machine in Java? (questions)
  • 20 System Design Interview Questions (list)
  • Difference between State and Strategy Design Pattern in Java? (answer)
  • Top 5 Courses to learn Design Patterns in Java (courses)
  • 5 Free Courses to learn Data Structure and Algorithms (courses)
  • My favorite courses to learn Software Architecture (courses)

Thanks for reading this article so far. If you like these design pattern interview questions then please share with your friends and colleagues. If you have any questions or feedback then please drop a note.

P. S. - If you are looking for some free courses to learn Design Pattern and Software Architecture, I also suggest you check out the Java Design Patterns and Architecture course by John Purcell on Udemy. It's completely free, all you need to do is create an Udemy account to access this course.

8 comments:

  1. The volatile keyword always existed in java, so what exactly has changed in 1.5 ?

    ReplyDelete
  2. With jdk 1.5 release, the implementation of volatile keyword also changed which makes it work with 1.5 and later. Refer this: http://singletonjava.blogspot.com/2015/12/java-singleton-design-pattern-double.html

    ReplyDelete
  3. thanks for this helpful article

    ReplyDelete
  4. I think you should also refer to the java segment of this wiki page:
    https://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Java
    It has a more in depth example WHY the half initialized left handed statement (the instance variable) can exist, it is not trivial WHY the compiler/interpreter in the background lets the runtime assign anything to the left side BEFORE the right side is fully made.

    ReplyDelete
  5. Please fix the spelling of the word volatile in the first code snippet.

    ReplyDelete