Sunday, September 24, 2023

Double Checked Locking on Singleton Class in Java - Example

Singleton class is quite common among Java developers, but it poses many challenges to junior developers. One of the key challenges they face is how to keep Singleton class as Singleton? i.e. how to prevent multiple instances of a Singleton due to whatever reasons. Double-checked locking of Singleton is a way to ensure only one instance of Singleton class is created through an application life cycle. As the name suggests, in double-checked locking, code checks for an existing instance of Singleton class twice with and without locking to double ensure that no more than one instance of singleton gets created.

By the way, it was broken before Java fixed its memory model issues in JDK 1.5. In this article, we will see how to write code for double-checked locking of Singleton in Java, why double-checked locking was broken before Java 5, and How that was fixed.

By the way, this is also important from an interview point of view, I have heard it’s been asked to code double-checked locking of Singleton by hand on companies in both the financial and service sector, and believe me, it’s tricky until you have a clear understanding of what you are doing. You can also see my full list of Singleton design pattern questions to prepare well.

Btw, In order to best understand design patterns, you need to work out some scenarios, examples, etc. It's best to get this kind of knowledge as part of your work but even if you don't get there, you can supplement them by joining a comprehensive course like these Design Patterns in Java courses and doing some object-oriented software design exercises. 



Why do you need Double-checked Locking of Singleton Class?

One of the common scenarios, where a Singleton class breaks its contracts is multi-threading. If you ask a beginner to write code for Singleton design pattern, there is a good chance that he will come up with something like the below :

private static Singleton _instance;

public static Singleton getInstance() {
        if (_instance == null) {
            _instance = new Singleton();
        }
        return _instance;
}

and when you point out that this code will create multiple instances of Singleton class is called by more than one thread parallel, he would probably make this whole getInstance() method synchronized, as shown in our 2nd code example getInstanceTS() method.



Though it’s thread-safe and solves issues of multiple instances, it's not very efficient. You need to bear the cost of synchronization all the time you call this method, while synchronization is only needed on first class, when Singleton instance is created.

This will bring us to double-checked locking pattern, where the only critical section of code is locked. Programmer call it double checked locking because there are two checks for _instance == null, one without locking and other with locking (inside synchronized) block.

Here is how double checked locking looks like in Java :

public static Singleton getInstanceDC() {
        if (_instance == null) {                // Single Checked
            synchronized (Singleton.class) {
                if (_instance == null) {        // Double checked
                    _instance = new Singleton();
                }
            }
        }
        return _instance;
}

On the surface, this method looks perfect, as you only need to pay price for synchronized block one time, but it has still broken until you make _instance variable volatile.

Without a volatile modifier, it's possible for another thread in Java to see half initialized state of _instance variable, but with volatile variable guaranteeing the happens-before relationship, all the write will happen on volatile _instance before any read of _instance variable.

This was not the case prior to Java 5, and that's why double-checked locking was broken before. Now, with happens-before guarantee, you can safely assume that this will work.

By the way, this is not the best way to create thread-safe Singleton, you can use Enum as Singleton, which provides inbuilt thread-safety during instance creation. Another way is to use a static holder pattern.

Double Checked Locking on Singleton in Java

/*
 * A journey to write double checked locking of Singleton class in Java.
 */

class Singleton {

    private volatile static Singleton _instance;

    private Singleton() {
        // preventing Singleton object instantiation from outside
    }

    /*
     * 1st version: creates multiple instance if two thread access
     * this method simultaneously
     */

    public static Singleton getInstance() {
        if (_instance == null) {
            _instance = new Singleton();
        }
        return _instance;
    }

    /*
     * 2nd version : this definitely thread-safe and only
     * creates one instance of Singleton on concurrent environment
     * but unnecessarily expensive due to cost of synchronization
     * at every call.
     */

    public static synchronized Singleton getInstanceTS() {
        if (_instance == null) {
            _instance = new Singleton();
        }
        return _instance;
    }

    /*
     * 3rd version : An implementation of double checked locking of Singleton.
     * Intention is to minimize cost of synchronization and  improve performance,
     * by only locking critical section of code, the code which creates
 instance of Singleton class.
     * By the way this is still broken, if we don't make _instance volatile,
 as another thread can
     * see a half initialized instance of Singleton.
     */

    public static Singleton getInstanceDC() {
        if (_instance == null) {
            synchronized (Singleton.class) {
                if (_instance == null) {
                    _instance = new Singleton();
                }
            }
        }
        return _instance;
    }
}

That's all about double checked locking of Singleton class in Java. This is one of the controversial way to create thread-safe Singleton in Java, with simpler alternatives available in terms of using Enum as Singleton class. I don't suggest you to implement your Singleton like that as there are many better way to implement Singleton pattern in Java.

Though, this question has historical significance and also teaches how concurrency can introduce subtle bugs. As I said before, this is very important from interview point of view. Practice writing double-checked locking of Singleton class by hand before going for any Java interview.

This will develop your insight on coding mistakes made by Java programmers. On related note, In modern day of Test driven development, Singleton is regarded as anti pattern because of difficulty it present to mock its behaviour, so if you are TDD practitioner better avoid using Singleton pattern.

And, now one thought provoking question for you? why Singleton is considered anti pattern now? What is the biggest disadvantage of using Singleton pattern in Java? And what is alternative of Singleton pattern?

26 comments:

  1. I like the way you explained some of the pitfalls with concurrency. On convenience point of view, there are much better way to create thread-safe singleton, which is faster, provides JVM level thread-safety guarantee and much more readable then double checked locking like patterns based upon class initialization, Enum based Singleton etc.

    ReplyDelete
  2. double checked locking is now considered as an anti-pattern and according to Doug Lea, you should avoid using it because the forces that motivated it e.g. slow uncontented synchronization and slow JVM startup are no loner an issue, making it less effective as an optimizaiton. They lazy initialization holder pattern offers the same benefit but it's easier to understand. bottom line is, there are lot of alternatives of Double check locking is available now without its drawback.

    ReplyDelete
  3. This is not completely thread safe. Please read the IBM JDK memory leaks where the JIT code optimization has been discussed. I know you are very studious and diligent and I need not say anything more for you to update this tutorial :)

    ReplyDelete
  4. /**
    Prof Bill Pugh, University of Maryland, was the main force behind java memory
    model changes. His principle Initialization-on-demand holder idiom also uses
    static block but in different way. It suggest to use static inner class.
    */
    public class Singleton {

    /**
    * Returns Singleton instance
    * @return Singleton
    */
    public static Singleton getInstance() {
    return InstanceHolder.INSTANCE;
    }

    // private constructor prevents instantiation from other classes
    private Singleton () {

    }

    // Maintains single instance of class
    private static class InstanceHolder {
    private static final Singleton INSTANCE = new Singleton();
    }

    }

    ReplyDelete
  5. java enum do perfectly the job, if you needn't lazy initialization ...

    ReplyDelete
  6. 4th Version

    public static Singleton getInstanceDC() { synchronized (Singleton.class) { if (_instance == null) { _instance = new Singleton(); } } return _instance; } }

    ReplyDelete
  7. Some one asked me interview that u have given double checked . if i remove 1st null check so what will happen..it told it will work..then they asked me why we are giving
    double check..what is the meaning of first null check..there i got stuck.so can u explain it...?

    ReplyDelete
  8. Hello Abhinav, if you notice, first null check is outside of synchronization block and second one is inside synchronization block. If you remember the purpose of double checked locking idiom was to improve performance of getInstance() method which was used to a synchronized method.

    In reality you need synchronization only when you create instance, and that's why first check is without synchronization it check and return instance without synchronization if already initialized.

    The second check is inside the synchronization to avoid thread-safety issue, if you don't use synchronization, if two thread access getInstance() same time, they might see different value or half initialized value of Singleton.

    In short, 1st check to speed up, 2nd check to avoid thread-safety issue.

    ReplyDelete
  9. Hi Javin,
    Can you explain me this statement "one without locking and other with locking (inside synchronized) block"?I did't get why we need the second if condition,as if we consider that 1st thread will enter sync block will create instance bcoz till now no instance get created.And when the instance get created,the other thread will not at all enter the second if condition,then whats the use of writing it.I googled every where but the same program but no good explanation.If possible please provide me with one.Thanks in advance.

    ReplyDelete
  10. @Samrat, you need second if condition because the first if check is without synchronization and it possible to see a partially constructed object, which is not null. In that case, second thread will wait until first thread leaves the synchronized block and then create another instance, replacing the first instance created by first thread, hence violating the meaning of Singleton pattern. Please see my post thread-safe singleton using double checked locking for more details, I have explained things in more details there.

    ReplyDelete
  11. I am trying to implement double check but getting this errorstatic UserPayments singletonInstance;

    public static volatile UserPayments getSingletonInstance() {

    if (null == singletonInstance) {
    synchronized (UserPayments.class){
    if (null == singletonInstance) {
    singletonInstance = new UserPayments();
    }
    }
    }
    return singletonInstance;
    }
    Illegal modifier for the method getSingletonInstance; only public, protected, private, abstract, static, final, synchronized, native & strictfp are permitted

    ReplyDelete
    Replies
    1. public static UserPayments getSingletonInstance() {

      Delete
  12. one more level of protection: override the clone method and throw exception for illegal operation. What say you???

    ReplyDelete
  13. Hi Javin..What we can write inside the private constructor or why we are using the private constructor, and what will happen if we will not write the constructor in Singleton class..?

    ReplyDelete
  14. Hi Javin,
    What is meant by "it's possible for another thread in Java to see half initialized state of _instance variable". Can you please explain in detail?

    ReplyDelete
  15. Hello @Sudarsan, half initialized state means some of the member variables are initialize others are not, in that case the reference comparison e.g. object == null may hold true.

    ReplyDelete
  16. Thanks Javin. so, you mean to say at first check, not in synchronized block?
    if (_instance == null) { // Single Checked

    ReplyDelete
  17. yes, that could be possible if we don't make _instance variable volatile.

    ReplyDelete
  18. Thanks Javin, for such a good explanation

    ReplyDelete
  19. Hello Abhilash, Thanks, Glad that you like my explanation. Please share with your friends too :-)

    ReplyDelete
  20. best detailed explanation sir! thanks

    ReplyDelete
  21. @Javin, inside synchronised block, only one thread presents and that creates an object, then in what scenario, this object will be in inconsistent state as once the object of this class is created, then all others will be using that very object, so why we are making that object Volatile.
    pls help me here.

    ReplyDelete
  22. Hello Unknown, if _instance is not volatile then one thread might see it partially initialized i.e. not null, which can cause problem. By declaring volatile it's guaranteed that all thread will see a consistent value for this variable.

    ReplyDelete
  23. Thanks Javin! Perfect explaination of Double checked locking!!

    ReplyDelete
  24. Can you please elaborate as if any exception occurs in singleton block by 1st thread then what should we do so that the object should be created at the end or how can I handle the exception in the method.

    ReplyDelete