Singleton Design Pattern

Singleton Design Pattern

In this tutorial, we are going to discuss about Singleton Design Pattern. Creating multiple objects of java class having same data is wasting memory, degrading performance. It is recommended to create one object and use it multiple times. The java class that allows us to create one object per JVM is called as singleton java class.

The Singleton design Pattern is a design pattern that restricts the instantiation of a class to one single instance. This is useful when exactly one object is needed to coordinate actions across the system. The Singleton design pattern is recognized by a method that creates a new instance of a class if one doesn’t exist. If an instance already exists, it simply returns a reference to that object.

Suppose multiple clients or parts of a system require access to a shared resource or service. There’s a risk of creating multiple instances of the resource or service. This can lead to inefficiencies, inconsistent states, or conflict issues if each client creates its own instance. For example, if each client created its own database connection, it could overwhelm the database server and cause connection management chaos.

Singleton Design Pattern 1

The Singleton design pattern addresses this problem by ensuring there is only one instance of a particular class (the Singleton), regardless of how many clients are trying to access it. In the above image, Singleton represents the class that enforces the single-instance rule, and Instance represents the single, shared instance. Each client (Client 1, Client 2, Client 3) is shown connecting to the same instance of the Singleton class, illustrating that they all share the same

Real-World Example

In a practical scenario, Singleton design pattern can be seen in a country’s central government concept. A country has one central government. This government is responsible for imposing all the rules and regulations, administering the nation, and implementing the policies throughout the country. No matter how many institutions or individuals interact with the government, they all engage in the same single instance.

Rules

To create the singleton class, we need to have following things.

1. Static member

It gets memory only once because of static, it contains the instance of the Singleton class.

2. Private constructor

It will prevent to instantiate the Singleton class from outside the class.

3. Static factory method

This provides the global point of access to the Singleton object and returns the instance to the caller.

We can create singleton class 7 ways

  1. Eager initialization
  2. Static block initialization
  3. Lazy Initialization
  4. Thread Safe Singleton
  5. Bill Pugh Singleton Implementation
  6. Using Reflection to destroy Singleton Pattern
  7. Serialization and Singleton
1. Eager initialization

In eager initialization, the instance of Singleton Class is created at the time of class loading, this is the easiest method to create a singleton class but it has a drawback that instance is created even though client application might not be using it.

package com.ashok.designpatterns.singleton;
/**
 * 
 * @author ashok.mariyala
 *
 */
public class MyEagerInitializedSingleton {    
   // Static member
   private static final MyEagerInitializedSingleton instance = new MyEagerInitializedSingleton();
    
   //private constructor to avoid client applications to use constructor
   private MyEagerInitializedSingleton(){}

   // Static factory method
   public static MyEagerInitializedSingleton getInstance(){
      return instance;
   }
}

If your singleton class is not using a lot of resources, this is the approach to use. But in most of the scenarios, Singleton classes are created for resources such as File System, Database connections etc and we should avoid the instantiation until unless client calls the getInstance() method. Also this method doesn’t provide any options for exception handling.

2. Static block initialization

This implementation is similar to eager initialization, except that instance of class is created in the static block that provides option for Exception Handling.

package com.ashok.designpatterns.singleton;

/**
 * 
 * @author ashok.mariyala
 *
 */
public class MyStaticBlockSingleton {
   // Static member
    private static MyStaticBlockSingleton instance;
    
   //private constructor to avoid client applications to use constructor
   private MyStaticBlockSingleton(){}
    
   //static block initialization for exception handling
   static{
      try{
         instance = new MyStaticBlockSingleton();
      }catch(Exception e){
         throw new RuntimeException("Exception while creating singleton instance");
      }
   }
    
   // Static factory method
   public static MyStaticBlockSingleton getInstance(){
      return instance;
   }
}

Both eager initialization and static block initialization creates the instance even before it’s being used and that is not the best practice to use.

3. Lazy Initialization

Here creation of instance when required.

package com.ashok.designpattens.singleton;
/**
 * 
 * @author ashok.mariyala
 *
 */
public class MyLazyInitializedSingleton {
   private static MyLazyInitializedSingleton instance;
   
   private MyLazyInitializedSingleton(){}
   
   public static MyLazyInitializedSingleton getInstance(){
      if(instance == null){
         instance = new MyLazyInitializedSingleton(); //instance will be created at request time
      }
      return instance;
   }
}

The above implementation works fine in case of single threaded environment but when it comes to multi threaded systems, it can cause issues if multiple threads are inside the if loop at the same time. It will destroy the singleton design pattern and both threads will get the different instances of singleton class. In next section, we will see different ways to create a thread-safe singleton class.

4. Thread Safe Singleton

The easier way to create a thread-safe singleton class is to make the global access method synchronized, so that only one thread can execute this method at a time. General implementation of this approach is like the below class.

package com.ashok.designpatterns.singleton;
/**
 * 
 * @author ashok.mariyala
 *
 */
public class MyThreadSafeSingleton {
   private static MyThreadSafeSingleton instance;
   
   private MyThreadSafeSingleton(){}
   
   public static synchronized MyThreadSafeSingleton getInstance(){
      if(instance == null){
         instance = new MyThreadSafeSingleton();
      }
      return instance;
   }   
}

In the above implementation works fine and provides thread-safety but it reduces the performance because of cost associated with the synchronized method, although we need it only for the first few threads who might create the separate instances. To avoid this extra overhead every time, double checked locking principle is used. In this approach, the synchronized block is used inside the if condition with an additional check to ensure that only one instance of singleton class is created. Following code snippet provides the double checked locking implementation.

public static MyThreadSafeSingleton getInstanceUsingDoubleLocking(){
   if(instance == null){
      synchronized (MyThreadSafeSingleton.class) {
         if(instance == null){
            instance = new MyThreadSafeSingleton();
         }
      }
   }
   return instance;
}
5. Bill Pugh Singleton Implementation

Prior to Java 5, java memory model had a lot of issues and above approaches used to fail in certain scenarios where too many threads try to get the instance of the Singleton class simultaneously. So Bill Pugh came up with a different approach to create the Singleton class using a inner static helper class. The Bill Pugh Singleton implementation goes like this;

package com.ashok.designpatterns.singleton;
/**
 * 
 * @author ashok.mariyala
 *
 */
public class MyBillPughSingleton {

   private MyBillPughSingleton(){}
   
   private static class MySingletonHelper{
      private static final MyBillPughSingleton INSTANCE = new MyBillPughSingleton();
   }
   
   public static BillPughSingleton getInstance(){
      return SingletonHelper.INSTANCE;
   }
}

Notice the private inner static class that contains the instance of the singleton class. When the singleton class is loaded, MySingletonHelper class is not loaded into memory and only when someone calls the getInstance method, this class gets loaded and creates the Singleton class instance.

This is the most widely used approach for Singleton class as it doesn’t require synchronization. I am using this approach in many of my projects and it’s easy to understand and implement also.

6. Using Reflection to destroy Singleton Pattern

Reflection can be used to destroy all the above singleton implementation approaches. Let’s see this with an example class.

package com.ashok.designpatterns.singleton;

import java.lang.reflect.Constructor;
/**
 * 
 * @author ashok.mariyala
 *
 */
public class MyReflectionSingletonTest {
   public static void main(String[] args) {
      MyEagerInitializedSingleton instanceOne = MyEagerInitializedSingleton.getInstance();
      MyEagerInitializedSingleton instanceTwo = null;
      try {
         Constructor[] constructors = MyEagerInitializedSingleton.class.getDeclaredConstructors();
         for (Constructor constructor : constructors) {
            //Below code will destroy the singleton design pattern
            constructor.setAccessible(true);
            instanceTwo = (MyEagerInitializedSingleton) constructor.newInstance();
            break;
         }
      } catch (Exception e) {
         e.printStackTrace();
      }
      System.out.println(instanceOne.hashCode()); // 366712642
      System.out.println(instanceTwo.hashCode()); // 1829164700
   }
}

When you run the above program, you will notice that hash code of both the instances are not same that destroys the singleton design pattern.

7. Serialization and Singleton

Sometimes in distributed systems, we need to implement Serializable interface in Singleton class so that we can store it’s state in file system and retrieve it at later point of time. Here is a small singleton class that implements Serializable interface also.

package com.ashok.designpatterns.singleton;

import java.io.Serializable;

/**
 * 
 * @author ashok.mariyala
 *
 */
public class MySerializedSingleton implements Serializable{

   private static final long serialVersionUID = -7604766932017737115L;

   private MySerializedSingleton(){}
   
   private static class SingletonHelper{
      private static final MySerializedSingleton instance = new MySerializedSingleton();
   }
   
   public static MySerializedSingleton getInstance(){
      return SingletonHelper.instance;
   }   
}

The problem with above serialized singleton class is that whenever we deserialize it, it will create a new instance of the class. Let’s see it with a simple program.

package com.ashok.designpatterns.singleton;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;

/**
 * 
 * @author ashok.mariyala
 *
 */
public class MySingletonSerializedTest {

   public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
      MySerializedSingleton instanceOne = MySerializedSingleton.getInstance();
      ObjectOutput out = new ObjectOutputStream(new FileOutputStream("ashok.ser"));
      out.writeObject(instanceOne);
      out.close();
      
      //deserailize from file to object
      ObjectInput in = new ObjectInputStream(new FileInputStream("ashok.ser"));
      MySerializedSingleton instanceTwo = (MySerializedSingleton) in.readObject();
      in.close();
      
      System.out.println("instanceOne hashCode="+instanceOne.hashCode());
      System.out.println("instanceTwo hashCode="+instanceTwo.hashCode());      
   }
}

Output

instanceOne hashCode=2011117821
instanceTwo hashCode=109647522
Applications of Singleton Design Pattern

In software design, the Singleton design Pattern is an age-old favorite pattern to use in many scenarios. Let’s discuss some of the common scenarios where it is used:

Configuration Management

Almost all of the software applications need some configuration settings to run. These settings should remain consistent throughout the application scope, whether they are loaded from a file or server. Using a Singleton design Pattern for configuration management allows us to make sure that:

  • There is a single source for configuration management.
  • Settings are initialized and loaded only once throughout the application lifecycle.
  • Various parts of the application can access these settings consistently.

Database Connection Pools

Efficient management of database connections is essential for the performance of an application. Singleton can help us with the following:

  • Rather than constantly opening and closing new database connections, it can reuse a pool of them.
  • It ensures efficient utilization and management with limited database connections.
  • It offers a consistent mechanism to access the database through various application parts.

Hardware Access Management

Singleton can help us with systems interfacing with some hardware resources like printers or graphics cards with the following:

  • Ensures there is synchronized access to the hardware, which prevents potential conflicts.
  • Offers a consistent interface for managing and controlling the hardware resource.
  • It manages the initialization and shutdown routine for the hardware, which reduces the overhead.

These are examples of scenarios where Singleton design Pattern can help us achieve efficiency in our software application.

Summary

In software engineering, the singleton design pattern is a popular design pattern that ensures a class has only one instance and offers a global point of access to this instance. It has benefits like lazy initialization, fewer global namespace issues, and restricted access to a single resource.

However, it has certain disadvantages, including potential for tight coupling, challenges with testing, scalability, and the introduction of hidden dependencies within an application. It should be used carefully, taking into account the influence on the design and maintainability of the program, even though it can be a useful pattern for managing shared resources and configurations.

That’s all about the Singleton Design Pattern. If you have any queries or feedback, please write us email at contact@waytoeasylearn.com. Enjoy learning, Enjoy Design patterns.!!

Singleton Design Pattern
Scroll to top