Singleton works on the concept of one and only one instance of the object, which results in the global control of a resource. In simple words, the Singleton design pattern ensures that only one instance of the class will be created and that instance will have global access within the application.

Singleton Design pattern is the most extensively used design pattern in java which comes under the creational design pattern. Singleton Design pattern is famous for its simplicity and the type of problem it solves.

A single instance of a class is achieved by defining the private constructor which will restrict the object creation And a static method to get the instance of the object which will be created inside the same class only.

The Java library uses the singleton pattern extensively. For example Runtime ,Logger ,Drivers,Threadpools.

When to use the singleton design pattern.

  • In the scenario to use the unique object of the class.
  • In the requirement of Global access over the object.
  • When you want a logging class to be used again and again by each and every class with in the application.
  • When you don’t want to repeat the objects unnecessarily.
  • Singleton class with synchronized method/block can manage the resources in the multithreaded environments.

Example of Basic Singleton Class.

In the Below class,Basicsingletonclass.java we created the private constructor which will restrict the object initiation of this class. We created a static method getInstance() that is creating the object only if the private attribute obj is not null.

package jstobigdata.designpatterns.singleton;

public class Basicsingletonclass {

  private static Basicsingletonclass obj = null;

  private Basicsingletonclass() {}

  public static Basicsingletonclass getInstance() {
    if (obj == null) {
      obj = new Basicsingletonclass();
    }
    return obj;
  }

}

Approaches of Singleton Design pattern.

In this section, we will discuss the different approaches to achieve the singleton pattern as per the requirement.

1. Static Block Approach:

In this approach, we create an instance of the object inside a static block. This is helpful when we want to handle exceptions while creating the singleton object.

package jstobigdata.designpatterns.singleton;

public class StaticblockSingleton {

  private static StaticblockSingleton obj;

  private StaticblockSingleton() {}

  static {
    try {
      obj = new StaticblockSingleton();
    } catch (Exception e) {
      throw new RuntimeException("Something gone Bad while creating singleton object");
    }
  }

  public static StaticblockSingleton getInstance() {
    return obj;
  }

}

2. Thread-safe Singleton:

In a multithreaded-environment, the above-defined simple singleton class may get failed. Here we need a different approach to handle this. To resolve this we use the double-checked locking, in which we first check if the object is null then inside the synchronized block we create a new object. The below example shows exactly the same.

package jstobigdata.designpatterns.singleton;

public class SingletonwithDoubleChecked {

  private SingletonwithDoubleChecked obj = null;

  private SingletonwithDoubleChecked() {}

  public SingletonwithDoubleChecked getInstance() {
    if (obj == null) {
      synchronized (obj) {
        obj = new SingletonwithDoubleChecked();
      }
    }
    return obj;
  }
}

3. Bill Pugh’s solution Approach (Lazy loading with inner class).

The scenario where a large number of threads try to get the instance of the singleton class simultaneously may lead to severe memory issues. As a solution to this problem, Bill pugh comes in the picture by defining the inner static class. The real approach to solving the problem is by creating the singleton instance only if the getInstance() method is called and not when the class is loaded.

Below is the class which describes how Bill Pugh’appcoach can be implemented:

package jstobigdata.designpatterns.singleton;

public class BullPughApproach {

  private BullPughApproach() {}

  //Inner class
  private static class Singlehelper {
    private static final BullPughApproach obj = new BullPughApproach();
  }

  public static BullPughApproach getInstance() {
    return Singlehelper.obj;
  }
}

4. Eager Loading

This is the most common and simple approach to use in a singleton class where the instance is created when the singleton class gets loaded. The drawback of this approach is that instance is created even if the client is not using this class.

package jstobigdata.designpatterns.singleton;

public class EagerLoading {

  private static final EagerLoading obj = new EagerLoading();

  private EagerLoading() {}

  public static EagerLoading getInstance() {
    return obj;
  }
}

Use-case of Singleton Design Pattern.

Let’s say we want to create a common class for database connectivity. This will be called very frequently to make the connection from the application to the database. So with a simple approach, every time the Db connection class is called there will be a new object created each time in the heap. This will surely lead to the memory leak and OutofMemroy Exception.

As a solution, we generate a Singleton class for Db connection so only one instance is created, no matter how many times it gets called for the database connectivity from different classes.

package jstobigdata.designpatterns.singleton.realworldexample;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class DbConnection {

  private static DbConnection instance;
  private Connection connection;
  private String url = "jdbc:mysql://localhost:3306/jdbc";
  private String username = "root";
  private String password = "root";

  private DbConnection() throws SQLException {
    try {
      Class.forName("org.mysql.Driver");
      this.connection = DriverManager.getConnection(url, username, password);
    } catch (ClassNotFoundException ex) {
      System.out.println("Something is wrong with the DB connection String : " + ex.getMessage());
    }
  }

  public Connection getConnection() {
    return connection;
  }

  public static DbConnection getInstance() throws SQLException {
    if (instance == null) {
      instance = new DbConnection();
    } else if (instance.getConnection().isClosed()) {
      instance = new DbConnection();
    }
    return instance;
  }
  
}

There could be several Pros and cons using the Singleton Design Pattern in Java. However, it is a must-know creational design pattern. I would love to hear your feedback in the comments below.

By |Last Updated: May 9th, 2020|Categories: Java™|