Java Singleton Pattern comes in the Creational Design Pattern. Singleton restricts the instantiation of a class & ensures that only 1 instance of the class exists in the JVM. Singleton pattern is used for logging, drivers objects, caching and thread pool.
Several approaches but the basic concepts are:
Private constructor: This will prevent anyone to instantiate the class
Private static variable: This is the only instance of the class
Static public method : Global access point for the outer world to get instance of this class
Eager Initialization - Created at time of class loading even though client application might not be using it
Static block initialization - Similar to eager initialization except for instance getting created in static block which has option for exception handling
Lazy initialization- Creates the instance in the global acess method
Drawbacks of lazy initialization - Works fine in single threaded environment
In multi-threaded environment it can destroy the singleton pattern if two threads get different instances of the class
So we will be creating thread-safe singleton class
Thread-safe Singleton Class - Make the global access method synchronized so that only 1 thread can execute this at a time
Drawback of Threadsafe Singleton - By using synchronized we prevent Thread 2 or Thread 3 to access the method while Thread 1 is inside the method. So every time the method is called there is additional overhead.
Double Checked Locking - To overcome the drawback of simple thread safe singleton, we use double checked locking to limit the expensive operation
Drawback of Double Checked Locking- To understand this, 1st we need to understand that object creation can be broadly classified into 3 steps:
Allocating memory to an object
Executing code inside the constructor
Assigning memory reference to the field
Problem is some of the JIT compilers reorder last 2 steps.
In that case instance variable will be assigned non-null reference & then constructor code will be executed
Half-baked object : If an object is assigned non-null reference & code inside the constructor is still being executed, then the object is not fully constructed/baked & is called half-baked object
Solution to this - We need to declare the instance variable as volatile
Because a volatile instance gurantees completion of all the steps of object creation before another thread reads the reference from the instance variable