Singleton Design Pattern in Java

Do not miss this exclusive book on Binary Tree Problems. Get it now for free.

To solve a few commonly faced problems in the computer science world, a few smart people invented design patterns - Singleton is one of them. It is the simplest of all the creational patterns. The patterns are called as creational design patterns, as they are related to object creation. As the name suggests, in this pattern, there can only be a single object of a class throughout the application life cycle.

What?! What on earth would we need only one object? How can we even restrict a class to create only a single object?

Let me answer the second question first: How to restrict a class with name say SingletonClass such that other classes will be allowed to create only a single object of this class?

Take a look at the class definition of SingletonClass class in Java. By the end of this article, we would have successfully converted it to a singleton class.

public class SingletonClass {

  public SingletonClass() {
      System.out.println("SingletonClass constructor called..");
  }

  public static void main(String[] args) {
       SingletonClass instance  = new SingletonClass();
  }
}

To answer above question, let me ask a couple more questions. How is the object of a class created? By calling a constructor of the class. Is there a way I could stop other classes from calling this constructor? Recalling that if private access modifier is applied to a function or variable in a class, the function or variable will remain accessible only in that class. So what if I make the constructor in the SingletonClass private?! No other class except itself will be able to call the constructor.

But we should be able to create at most one object of SingletonClass. By using this object, other classes will be able to call methods in this class. So what if we create an object of SingletonClass inside itself and provide a static method with name say which returns this object. Voila!

public static SingletonClass getInstance() {
  //returns an instance or object of SingletonClass
  return new SingletonClass();
}

Now, we have a method that will return the only object to other classes. Hold on a second. How are we supposed to call this method when we don't have the object of the class? We were calling this method to get the object in the first place. Well, notice static keyword. Recall that we don't an object to class a static method, we use the class name for that purpose as follows:

SingletonClass instance = SingletonClass.getInstance();

Did you notice any problem with the getInstance() method? Notice that every time this method is called, a new object of SingletonClass will be returned. This situation is against the rules.At any time, until the application in which the Singleton class exists is running, there must be the only object of this class. So, how about creating an object beforehand and then returning the same object every time getInstance() method is called. This is called as 'early initialization.' Following this concept, our SingletonClass will look like this:

public class SingletonClass {

  private static SingletonClass instance = new SingletonClass();

  private SingletonClass() {
      System.out.println("SingletonClass constructor called..");
  }

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

Notice that the object is marked as private and static. We marked it static since the method getInstance() is static as well. If we hadn't marked it static, we would get a compile error as "Non-static field 'instance' cannot be referenced from a static context."

Now, some might have an objection to this early initialization concept. Why assign the memory for the object even before it is needed? What if getInstance() is not called at all? The memory assigned to it is a waste. To avoid this situation, there is another way of initializing the object of a Singleton class, called 'lazy initialization.'

Take a look at the getInstance() method from the following class:

public class SingletonClass {

  private static SingletonClass object;

  private SingletonClass(){
      System.out.println("SingletonClass constructor called..");
  }

  public static SingletonClass getInstance() {
      //check if object exists already
      if(object == null) {
          //if it doesn't exist, create it
          object = new SingletonClass();
      }
      //return already existing object of SingletonClass
      return object;
  }
}

Here we are only initializing the object only when getInstanct() is called. Also noticed that we are checking object for being null before creating an object. It will ensure that we create an object only once. If it already exists, we will simply return the already existing object.

Great! Until now, we learned that there are two ways to create an object only once and make it accessible to other classes: early initialization and lazy initialization.

However, you might have noticed a problem with 'lazy initialization if you are familiar with multithreading concepts.'

Consider, two threads executing the getInstance() method

  public static SingletonClass getInstance() {

      //check if the object exists already
  /*T2*/  if(object == null) {
          //if it doesn't exist, create it
  /*T1*/    object = new SingletonClass();
      }
      //return already the existing object of SingletonClass
      return object;
  }

Consider that T1 is currently executing the code the constructor, and creating an object is under progress. At this particular moment, T2 is checking if the object is null; it will find that object is, in fact, null as T2 hasn't completely created an object yet. Now, T1 will also start executing the constructor. Thus, we have two objects in memory, and the single object constraint is no longer valid. Are you thinking about making T2 wait while T1 has finished executing getInstance() method? You are on the right track!

We need to do a small addition on the getInstance() method. Have you heard of synchronized keyword in Java? It exactly does what we want to achieve. When one thread is executing a method, it puts kind of a lock on the method, and another thread has to wait till the first thread finishes the method execution. So check the updated SingleClass with 'thread-safe lazy initialization' design.

public class SingletonClass {

  private static SingletonClass object;

  private SingletonClass(){
      System.out.println("SingletonClass constructor called..");
  }

  public static synchronized SingletonClass getInstance() {
      //check if object exists already
      if(object == null) {
          //if it doesn't exist, create it
          object = new SingletonClass();
      }
      //return already existing object of SingletonClass
      return object;
  }
}

Now that we know how to create a singleton class. Let's glance at a few real-world situations where we need to use this design pattern. In this design pattern, since we are creating the object only once, it makes sense if we used it when object creation is computation heavy.

Another common use case is a resource allocator. Consider a scenario where there are multiple printers (resources) at a cyber cafe. Multiple users want to print their documents using this printers. You have a print spooler which allocates printer to a user. Now, if you have two spoolers, it could happen that both the spoolers assign same printer to multiple users. Refer the diagram.

To avoid this situation, we must ensure that we have a single print spooler. Now this is a ideal use case for singleton design pattern.Following are the common use cases:

  1. Logging utility
  2. Database connectors

Here are the examples of Sigleton classes which are present in Java API:

  1. System
  2. Runtime
  3. Desktop

(Note: If you check the official Java documentation of above classes, you will not find a constructor, as it is private. Also, you will find a method similar to the getInstance() method we wrote.)

With this article at OpenGenus, you must have the complete idea of singleton class in Java. Enjoy.

Sign up for FREE 3 months of Amazon Music. YOU MUST NOT MISS.