Singleton Design Pattern

·

4 min read

Before understanding what is singleton design pattern, first let us understand what is singleton object.

In any of the application, whatever the objects we create we can create it in different ways. So, within your application you want to create your object only one time, at that time we will go for singleton object.

To create an object as a singleton we have to follow few properties.

  • Whenever we are defining the object of the class, we should only be having only one object.

  • We should not allow objects to be created using constructors. By making constructors as Private.

  • But we should allow class to create object ones, so for that, we have to create one static method.

Types to create Singleton Design Pattern

  1. Lazy-Singleton Instantiation

  2. Eager-Singleton Instantiation

  3. Multi-threaded Singleton

  4. Serializable-singleton

Now let us understand each of the above mentioned design patterns

  1. Lazy-Singleton Instantiation
  • Lazy initialization mean application will create instance when it is requested.

  • This can be used when you have a non-thread-safe application.

  • If we use this in Multi-thread application, it might get break, because our getInstance() method gets invoked by two/multiple threads at the same time.

When To Use

  • When you are creating non-thread safe application

  • When you are creating common resources like DB-Connections

Example Code

public class LazySingleton implements Serializable {

 /**
  * Default SerialVersionId
  */
 private static final long serialVersionUID = 1L;
 private static LazySingleton instance = null;

 private LazySingleton() {

 }

 public static LazySingleton getInstance() {
  if (instance == null) {
   instance = new LazySingleton();
  }
  return instance;
 }
}

2. Eager-Singleton Instantiation

  • Eager-Singleton — will solve the problem which we are facing in Lazy-Singleton

  • In Eager-Singleton Instantiation, as soon as JVM starts, the object will be created irrespective of whether it got accessed by any code in the application or not.

When To Use

  • Eager-Singleton Instantiation, can be used consider your application has some static cache related code and which needs to be get called as soon as JVM starts, in that cases it can be used.

Drawback

  • As mentioned above, it consumes resources, even if application does not use it.

Example Code

public class EagerSingleton {

 private static final EagerSingleton instance = new EagerSingleton();

 private EagerSingleton() {
  // to do the init() functionalities here
 }

 public static EagerSingleton getInstance() {
  return instance;
 }
}

3. Multi-threaded Singleton

  • As mentioned earlier, In Lazy-Singleton Initialization, if our get instance method invoked by two threads at the same time, then there are chances of creating two objects. Which violates singleton Design pattern Principle.

  • To avoid this problem, we can go-ahead with two choices

  1. Create getInstance() as synchronized so that, only one instance can invoke that method

  2. By using synchronized block

  • There is also a disadvantage, in using the first method which is creating getInstance() as synchronized, because consider there are 3 threads, where T1 is inside getInstance() and T2 and T3 are in waiting stage.

  • Now T2 will get into method and return the instance created by T1 and T3 will be in waiting stage.

  • So this leads to unnecessary thread locks

So, the below example code is created using synchronized block

public class MultiThreadedSingleton {

 private static MultiThreadedSingleton instance = null;

 private MultiThreadedSingleton() {

 }

 public static MultiThreadedSingleton getInstance() {
  if (instance == null) {
   // Our method is static, so we have class level locking here
   synchronized (MultiThreadedSingleton.class) {
    if (instance == null) {
     instance = new MultiThreadedSingleton();
    }
   }
  }
  return instance;
 }
}

4. Serializable-Singleton

  • As you already know, Serialization is used to convert an object of a byte stream

  • In this example, consider you have a singleton class which is implementing Serialization (Serializable)

  • Now if you serialize an object and deserialize, it will create a new object every time in the traditional approach.

  • To overcome this problem, we are using readResolve() method, which will ensure that to return the same instance during deserialize as well.

public class SerializableSingleton implements Serializable {

 /**
  * 
  */
 private static final long serialVersionUID = 1L;
 private static SerializableSingleton instance = null;

 private SerializableSingleton() {

 }

 public static SerializableSingleton getInstance() {
  if (instance == null) {
   instance = new SerializableSingleton();
  }
  return instance;
 }

 /**
  * This is the key method responsible during deserialization, even if not call
  * this, jvm will call internally and pass some other values instead we can
  * return the same instance object
  */

 protected Object readResolve() {
  return instance;
 }

}

I hope you found this article insightful and valuable. Your support means a lot to me — please feel free to share your thoughts, feedback, or suggestions in the comments.

If you enjoyed reading, don’t forget to clap, comment and share it with others who might benefit. Your encouragement inspires me to create more such content. Thank you