Singleton design pattern:
The Singleton design pattern involves only one class throughout the application
that is responsible for instantiating itself to make sure it creates no more than
one instance.
At the same time, it provides a global point of access to that instance.
In this case, the same instance can be used from everywhere, being impossible to directly invoke the constructor each time as the constructor is declared private.
Various kinds of implementations of Singleton:
1) Eager Initialization
In eager initialization, the instance of Singleton Class is created at the time of
class loading. This is the easiest method to create a Singleton class, but it has the
drawback of the instance being created even though client application might not be
using it.
2) Static Block Initialization
Static block initialization is similar to eager initialization, except that the
instance of the class is created in the static block that provides the option for
exception handling.
3) Lazy Initialization
Lazy initialization is a method to implement the Singleton pattern to create an
instance in the global access method - the factory method / getter method.
This implementation works fine in case of a single-threaded environment, but when
it comes to multithreaded systems, it can cause issues if multiple threads are
inside the if loop at the same time. It will destroy/break the singleton pattern, and
both threads will get the different instances of the singleton class.
4) Thread-safe Singletons
The easier way to create a thread-safe singleton class is to make the global access method synchronized so that only one thread can execute this method at a time.
This implementation works fine and provides thread-safety, but it reduces
performance because of the cost associated with the synchronized method, although we need it only for the first few threads that might create the separate instances.
To avoid extra overhead, we use Double-checked Locking principle.
5) Double-Checked Locking
In this approach, the synchronized block is used inside the 'if condition' with an additional check to ensure that only one instance of the singleton class is created.
Let's see how. Suppose there are two threads, T1 and T2. Both come to create
an instance and execute “instance==null”.
Now both threads have identified the instance variable as null, and thus assume that
they must create an instance.
They sequentially go to a synchronized block and create the instances.
In the end, we have two instances in our application.
6) Bill Pugh Solution
This principle uses static blocks but in a different way.
It suggests using static inner class, where this class contains the instance of singleton class. When the singleton class is loaded, the SingletonHelper(inner) class
is not loaded into the memory, rather it loads only when someone calls the
getInstance() method. At this time, the class gets loaded and creates the Singleton class instance. Most widely used approach that doesn't require synchronization.
What destroys/breaks the Singleton design pattern ?
Reflection and Serialization/Deserializaion process destroys the Singleton design pattern.
Comments