top of page
Writer's pictureNithya Gunasekaran

Singleton Design Pattern

This is a very important topic in java programming. Singleton Design Pattern is used to make sure that only one instance or object is created in JVM for particular class and that instance is accessed in other classes.


Let's learn about what is the purpose is of this singleton design pattern.



Different ways of Creating Singleton Class:

  • Eager Initialization.

  • Lazy Initialization.

  • Synchronization Method.

  • Double Check Lock (There is memory issue, resolved through volatile instance variable.


Eager Initialization:

As the name says eager means something in advance, the instance of singleton class is created once when the class is loaded. As soon as the application starts, all the static variables are preloaded into the memory. That's why it is called Eager Initialization. Even though there is no class that uses this instance, the object is still created and stored in memory.


package singleton_design_pattern;

public class EagerSingletonClassFile {

// Create a private static instance

private static EagerSingletonClassFile singletonObj = new EagerSingletonClassFile();

// create a private Constructor

private EagerSingletonClassFile() {

}

// static method to get the instance

public static EagerSingletonClassFile getInstance() {

return singletonObj;

}

}


Disadvantage:

Even though there is no class using this object, the memory is created. So to overcome this problem, Lazy Initialization has come in to the picture.


Lazy Initialization:

In lazy Initialization, the instance is created only when it's needed meaning when caller asks for instance we will check for existing instance and if instance is not available then it will create memory and return the instance or else simply it will return the existing instance.


Comparing Lazy Initialization with Eager:

In the below Picture-A Line 6 we initialize the object

EagerSingletonClassFile singletonObj = new EagerSingletonClassFile();

in the below Picture-B line 7 we just initialize the object name as null.


LazyInitializationSingleton singletonObj = null;

The instance is assigned to null in picture B on line 7. Now look at Picture B in line 17 the object is declared.

singletonObj = new LazyInitializationSingleton();


While executing Thread 1, it will come inside the getinstance method, the object is null because its calling for the very first time and it will create the object. Thread 2 is coming inside the loop. Here the object is created already, the object is not null. So line 19 will return the already created object. This is the concept of Lazy Initialization. The object is private . It can be called any number of times in other classes.


LazyInitializationSingleton singletonObj =LazyInitializationSingleton.getintance();


In Line - 10 (Picture A ) the constructor is still private because it wont allow to create an object outside of the class.

    

Picture A:

Eager Initialization code:


Picture B:

Lazy Initialization code:



package singleton_design_pattern;

public class LazyInitializationSingleton {

// Create a private static instance

private static LazyInitializationSingleton singletonObj = null;

// create a private Constructor

private LazyInitializationSingleton() {

}

// static method to get the instance

public static LazyInitializationSingleton getInstance() {

if(singletonObj == null) {

singletonObj = new LazyInitializationSingleton();

}

return singletonObj;

}

}


The disadvantage is what if two threads come in parallel at the same time, then the singletonObj will be null at the same time, they will check and now the two object will created now. so this disadvantage of Lazy Initialization Singleton pattern. To overcome this problem, there is next pattern called Synchronized Method.


Synchronized Method:

Synchronized methods will make sure there is only one thread executing at a time and ensure no parallel thread executes the block at the same time.

In the blow picture, if you see in the line 14, synchronized method will does two things. It will first put a lock and then unlock for the threads while accessing its method at the same time. Now only one Thread will be allowed to go inside this method, so Thread 1 will go inside the method and see the singletonObj is null. It will create the new object, assigned to Thread 1. It's time to proceed with the Thread 2. Now the Thread 2 will go inside this method and the object is already created, so it won't be null. Then line 18 will return the object to the Thread 2.



package singleton_design_pattern;

public class SynchronizedSingleton {

// Create a private static instance

private static SynchronizedSingleton singletonObj = null;

// create a private Constructor

private SynchronizedSingleton() {

}

// synchronized method to get the instance

synchronized public static SynchronizedSingleton getInstance() {

if(singletonObj == null) {

singletonObj = new SynchronizedSingleton();

}

return singletonObj;

}

}


The disadvantage of this synchronized method is that we are putting entire method as synchronized so execution will be slow. Why is it slow ? We are calling this getInstance method in so many places. So every time we call this method, this keyword will lock and unlock to give the object. Suppose we call 25 times, all the 25 times the synchronized block will lock and unlock. So this leads to very slow while executing the scripts.. To overcome this the Double Check Lock in systems plays the role now.


Double Check Lock :

In the picture below when you see the line 14 and line 16 has the check 1 and check 2. That's why it is called a Double check lock. If you run the suite, first it will check if the object is null in

line-14, yes it is null and then in line 15, if you see there is synchronized come into the picture, now synchronized will put the lock and check still the object is null, yes it is null then it will create an object. Now Thread -2 comes in line 14. See if its not null, then it will return to the already created object.


So it will solve the problem of concurrence, which will say, for example, now the line 5 object is null and two threads come at the same time T1 and T2 both will see null in line -5 and they will come into the getInstance method and line 14 say null for both Thread -1 and Thread -2, line 15 has synchronized so the Thread -1 will go inside the loop and check the object is null, yes it is null so the object is created now asynchronized will unlock the Thread -1 and then next

Thread -2 will lock and get in to loop and do the Double Check, find the object is not null so it will return the already created object.



package singleton_design_pattern;

public class DoubleCheckedLockingSingleton {

// Create a private static instance

private static DoubleCheckedLockingSingleton singletonObj = null;

// create a private Constructor

private DoubleCheckedLockingSingleton() {

}

// Doubled Check Lock method to get the instance

public static DoubleCheckedLockingSingleton getInstance() {

if (singletonObj == null) {

synchronized (DoubleCheckedLockingSingleton.class) {

if (singletonObj == null) {

singletonObj = new DoubleCheckedLockingSingleton();

}

}

}

return singletonObj;

}

}


The disadvantages of this Double Check Lock are having memory issue. This issue is solved by using the volatile keyword in line 5 to overcome the memory issue. whenever if you use the Double Check Lock you can use with the volatile keyword to avoid the issue happen in memory. But still the execution will gets little bit slow.



Conclusion:

In this Singleton design pattern we have learned all kinds of patterns, advantages and disadvantages of using each pattern and understanding the different ways to implement this pattern and knowing that use cases can help you create efficient and maintainable code. We also learned about the thread safety strategies and the instance is globally accessible.




15 views

Recent Posts

See All
bottom of page