Double-checked locking pattern is one of the interesting topics in Java Interviews. Earlier, it was asked to see if a 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 the 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 patterns like how to code them, how they work, the 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
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 because volatile provides the happens-before guarantee and when a volatile read is happening the memory barrier is refreshed as explained in Java Concurrency in Practice as well.
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 a 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 the lifespan of Singleton. That's why you get the performance boost becuase locking only happens one time during the lifespan of the Singleton instance.
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.
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
Double Checked Locking Example in Java
Here is one example of a thread-safe Singleton class in Java using a 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 because volatile provides the happens-before guarantee and when a volatile read is happening the memory barrier is refreshed as explained in Java Concurrency in Practice as well.
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 a 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 the lifespan of Singleton. That's why you get the performance boost becuase locking only happens one time during the lifespan of the Singleton instance.
Why is 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 checkpoint. 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 comes to 1st checkpoint which is not synchronized, now there is a possibility that it can see a 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, writing to a volatile field will happen before any read, which negates the possibility of seeing half initialized instances of the Singleton class.
See Applying Concurrency and Multi-threading to Common Java Patterns for more details on the happens-before guarantee.
Safe alternatives of Double-checked Locking Pattern
If the getInstance() method is not a bottleneck then the simplest way to avoid Double-checked locking is to make the whole method synchronized. Java has come a long way in performance and the penalty to synchronizing is a lot lesser than what it used to be.Other alternative includes using Enum as Singleton in Java. Enum guarantees a lot of features required by Singleton pattern out-of-the-box like initialization to Enum constants are thread-safe, Enum also provides Serialization guarantee that only one instance of Singleton will exit 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 then this idiom works quite well.
class EagerSingleton { public static EagerSingleton singleton = new EagerSingleton (); }
One more alternative of double-checked locking is the Initialization on Demand Holder idiom, which uses an inner class to encapsulate Singleton instance. This idiom takes advantage of the fact that the Inner class is not loaded until they are referenced.
You can still use a 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 modifier on the Singleton instance.
Here is a nice diagram to remember how to implement double-checked locking for Singleton in Java:
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.
Other Java Design Patterns tutorials you may like
Thanks for reading this article so far. If you like this double-checked locking of singleton tutorial and my explanation then please share them 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.
Other Java Design Patterns tutorials you may like
- Top 5 Courses to learn Design Pattern in Java (pattern 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 Software Architecture 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 this double-checked locking of singleton tutorial and my explanation then please share them 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.
The volatile keyword always existed in java, so what exactly has changed in 1.5 ?
ReplyDeleteWith 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
ReplyDeletegreat article
ReplyDeleteThank!! you Rajeev
Deletethanks for this helpful article
ReplyDeleteI think you should also refer to the java segment of this wiki page:
ReplyDeletehttps://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.
Please fix the spelling of the word volatile in the first code snippet.
ReplyDeleteOk, Thanks for pointing out.
Delete