Singleton Design Pattern


Singleton Design Pattern

Singleton design pattern falls under creational design pattern category which restricts a class to have only one instance and provide global access. 

Singleton design pattern is a famous design pattern and often asked in interviews. It is very simple and has a lot of use cases involving object reuse like Database Connections. Instead of instantiating a database connection everytime one needs to run a database query, one can create a singleton database connection and reuse the same database object for executing queries. 

In this article, let's explore various different ways for creating a singleton and their code implementations in Java. 

There are four ways, I am going to discuss to create a singleton.

  1. Eager Initialization
  2. Eager Initialization with exception handling
  3. Lazy Initialization with synchronized keyword.
  4. Lazy Initialization and threadsafe without using synchronized keyword.

Eager Initialization

To create singleton class, we must make the constructor private. By making the constructor private, we are not allowing any class to instantiate an object. 

How are we going to get an instance of an object then?

We are going to instantiate the object within the class and return it via public method or a public static final field.  Eager Initialization means regardless of usage, a singleton object is going to be created. 


Here, we are going to use public static final field and initialize the object. The static fields gets initialized only once i.e when the class is loaded. 

It is a variable which belongs to the class and not to object(instance).  Static variables are initialized only once, at the start of the execution. 

A single copy to be shared by all instances of the class. A static variable can be accessed directly by the class name and doesn’t need any object.


Eager Initialization with exception handling

A disadvantage of above initialization is there is no exception handling. If we are supposed to read a configs file, if the file doesn't exist it will throw an IO Exception. There is no Exception handling if we initialize the object in the above manner. 

A neat approach is to initialize in a static block as static blocks gets executed before static variables.


Lazy Initialization

Lazy Initialization means an object will be created only when called upon. This saves memory compared to Eager Initialization. If we take an example of a class which initializes a lot of objects. Regardless of its usage, in eager initialization an object will be created. If it is not used, it will be a wastage of memory. 


Above code is an lazy initialization example in java where an object is initialized only when getInstance() method is called upon. 

However, the above code is not thread safe. When both threads simultaneously tries to call the getInstance() method, each thread may end up with creating a separate instance each. 


How to make it thread safe? 

Using synchronized key word.  We can use synchronized keyword over method to restrict only one thread entering the if block and initializing the object.  However, this is a bit slower if even after initializing the object, second thread has to wait until the first thread exits. 


This can be made faster by using synchronized block like in getInstanceViaDoubleCheckLocking(String value) method below. 

  

Lazy Initialization and threadsafe without using synchronized keyword.

This way of singleton initialization is been around since Java 5 which is based on the Java Language Specification.  

Lazy Initialization is provided by a private constructor which restricts from initializing object from  outside the class.

According to Java language Specification, static data members are loaded into JVM only when called.  A static inner class is not a static data member. The class loader considers there are no static fields in the class. 

Java language specification guarantees sequential execution of the class initialization. This provides thread safety.  

No explicit synchronization needed on getInstance() method for loading and initialization.

When  two threads call getInstance() method, because of sequential execution of class initialization, only first thread instantiates the object.

On the other hand,  since the static field is already initialized, second thread will get the same object. Since the object is final, it cannot  be modified.

Keep Experimenting 🔎 

Keep Learning 🚀


Post a Comment

Previous Post Next Post