Singleton
Singleton is most important and frequently used design pattern in java . It restricts the instantiation of a class and ensures that only one instance of the class exists in the java virtual machine. To be precise , in a particular jvm there can be only one instance of this kind of class .
This kind of class provides a global access point of the class as it does not allow to create multiple instance of the class . This pattern is useful for logging , driver object , caching , thread pool .
There are different approaches to implement singleton classes . But all of those approaches consist of following rules in common :
- Private constructor to restrict instantiation of the class from other classes.
- Private static variable of the same class that is the only instance of the class.
- The global access point to instantiate the class is a public static method returning an instance of the class.
Lets discuss about those approaches and their corresponding advantage and disadvantages one by one.
Eager Initialization :
First and simple approach to create a singleton class is Eager Initialization . Lets look into an example of Eager initialization and then will explain that in brief .
Significance of this method :
Another easy implementation of singleton class is static block initialization . This implementation is almost similar to the eager initialization . Only difference is to instantiate the class in a static block with exception handling mechanism. Example of static block initialization is as follows :
Lazy Initialization :
Lazy initialization implies delay in initialization of object or block till the object is not required in runtime . In case of Eager initialization instance of the class is getting created at the time class loading . But in Lazy initialization method instance will be created only when user will call global access point of the class for the first time .
Example of lazy initialization is :
In this method instance is created inside the global static method getInstance . To ensure one instance null check has been performed on the instance variable before creating new instance of the class. So it will create one instance only on first invocation of the getInstance method.
This method works well in single threaded application , but in case of multi threaded application there is a chance of multiple thread can invoke getInstance method at the same instance . In that case all those thread will end up creating one instance of the class which violates definition of singleton class. This drawback can be tackled by either using synchronized getInstance method or creating instance within a synchronized block inside the if block . Now both the ways has corresponding drawback. Let me explain both of them.
Now look at the method carefully . Here synchronized method getInstance will be called every time , but actually we need synchronization only on the first invoke of the method. So basically though this method overcome the drawback of lazy initialization , it is not optimized solution.
Now the second solution :
This solution works fine normally . Now consider two threads comes into the if block at the same instance . What will happen then ? Obviously both the thread will create two different instances and violates the definition of singleton class. This problem can be solved by Double-checked locking pattern .
Double-checked locking pattern :
Double-checked locking pattern ensures that even if multiple threads pass null check there should be only one instance in JVM . It has been achieved by implementing another null check inside the synchronized block . Hence even if multiple method pass the first null check , they will fail second null check.
Also best practice is to add volatile keyword to the instance variable declaration .
This implementation looks perfect . But most optimized and easy concurrent lazy initialization implementation is Initialization on Demand Holder ( IODH ) design .
Initialization on Demand Holder ( IODH ) :
Initialization on Demand Holder is also know as Bill Pugh implementation . This is the most simple and easy implementation of lazy initialization of singleton implementation with high concurrency and good performance .
In IODH implementation , instance will not be created at the time of class loading of SingletonTest . The private static class SingletonHolder will not be initialized at that time . It will only be executed when public static method getInstance will be invoked for the first time and initialization of the inner class will initialize the static instance of the SingletonTest by private constructor of the class . JLS ( Java Language Specification ) ensures that no further synchronization is required in the getInstance method during loading and initialization phase .
This process is much faster than Double-checked locking pattern method and also removes overhead of synchronization .
Enum based Singleton implementation :
Most advance singleton implementation is using Enum . Java ensures that enum values are accessible globally and can be instantiated only once in JVM . Lets implement Enum based singleton class.
Enum implementation in Java handles all the pros and cons discussed in above methods.
Advantages of Enum implementation are :
Eager Initialization :
First and simple approach to create a singleton class is Eager Initialization . Lets look into an example of Eager initialization and then will explain that in brief .
| Eager Intialization |
Significance of this method :
- Constructor is private . So no other class can instantiate the class .
- It creates an instance of the class marked as static . That means this instance will be created at the time of class loading in the JVM.
- Public method getInstance() is the global access point to instantiate the class . It returns the static and final instance of the class .
- As the instance is marked as static , this method creates instance of the class even when user does not required. If singleton class uses lots of resources , this method is not efficient to be implemented. In that case we should use lazy initialization of the class.
- Final modifier ensures good optimization and thread safety as it is always a good design to make singleton instance immutable even though we are providing only constructor and no setter for the same.
Another easy implementation of singleton class is static block initialization . This implementation is almost similar to the eager initialization . Only difference is to instantiate the class in a static block with exception handling mechanism. Example of static block initialization is as follows :
| Static block initialization |
Lazy Initialization :
Lazy initialization implies delay in initialization of object or block till the object is not required in runtime . In case of Eager initialization instance of the class is getting created at the time class loading . But in Lazy initialization method instance will be created only when user will call global access point of the class for the first time .
Example of lazy initialization is :
| Lazy Initialization |
In this method instance is created inside the global static method getInstance . To ensure one instance null check has been performed on the instance variable before creating new instance of the class. So it will create one instance only on first invocation of the getInstance method.
This method works well in single threaded application , but in case of multi threaded application there is a chance of multiple thread can invoke getInstance method at the same instance . In that case all those thread will end up creating one instance of the class which violates definition of singleton class. This drawback can be tackled by either using synchronized getInstance method or creating instance within a synchronized block inside the if block . Now both the ways has corresponding drawback. Let me explain both of them.
| synchronized method |
Now look at the method carefully . Here synchronized method getInstance will be called every time , but actually we need synchronization only on the first invoke of the method. So basically though this method overcome the drawback of lazy initialization , it is not optimized solution.
Now the second solution :
| synchronized block |
This solution works fine normally . Now consider two threads comes into the if block at the same instance . What will happen then ? Obviously both the thread will create two different instances and violates the definition of singleton class. This problem can be solved by Double-checked locking pattern .
Double-checked locking pattern :
Double-checked locking pattern ensures that even if multiple threads pass null check there should be only one instance in JVM . It has been achieved by implementing another null check inside the synchronized block . Hence even if multiple method pass the first null check , they will fail second null check.
| Double-checked locking pattern |
Also best practice is to add volatile keyword to the instance variable declaration .
This implementation looks perfect . But most optimized and easy concurrent lazy initialization implementation is Initialization on Demand Holder ( IODH ) design .
Initialization on Demand Holder ( IODH ) :
Initialization on Demand Holder is also know as Bill Pugh implementation . This is the most simple and easy implementation of lazy initialization of singleton implementation with high concurrency and good performance .
| IODH |
In IODH implementation , instance will not be created at the time of class loading of SingletonTest . The private static class SingletonHolder will not be initialized at that time . It will only be executed when public static method getInstance will be invoked for the first time and initialization of the inner class will initialize the static instance of the SingletonTest by private constructor of the class . JLS ( Java Language Specification ) ensures that no further synchronization is required in the getInstance method during loading and initialization phase .
This process is much faster than Double-checked locking pattern method and also removes overhead of synchronization .
Enum based Singleton implementation :
Most advance singleton implementation is using Enum . Java ensures that enum values are accessible globally and can be instantiated only once in JVM . Lets implement Enum based singleton class.
| Enum |
Enum implementation in Java handles all the pros and cons discussed in above methods.
Advantages of Enum implementation are :
- Enum instantiation happens only once .
- Enum implementation is thread safe by default .
Comments
Post a Comment