Singleton Design pattern examples in java

Singleton Design Pattern in Java

The Singleton design pattern in Java is employed to maintain a single instance of an object within a system. This is particularly useful to avoid unnecessary overhead when creating multiple instances of an object in heap memory.

Let’s see an Problem and issues without this pattern.

When we use the new Object() code to construct an object, one new instance is created; however, if we call these, several instances are created in heap memory. If the number of calls to new objects increases, the size of the object in heap memory grows, causing performance overhead.

To prevent this, we’ll create a single object for all calls and return the same object.

Simple singleton Implementation:-

The basic steps for a simple singleton implementation include:

  • Private Constructor: To instantiate the class only within itself, preventing external instantiation.
  • Private Static Variable: A static variable that is an instance of the same class.
  • Static Method: A static method to check the static variable. If it is null, create an object; otherwise, return the existing object.

But, There are multiple ways that can be written to load eager or lazy loading.

Eager loading singleton example

Eager loading implies that a singleton class instance is created as soon as the class loads into memory. This results in a single instance being created during application startup.

Notes:

Regardless of whether the instance is needed, it is created during startup. If there is an expensive resource operation, the load time and startup time are increased. This approach is not useful if a class is not required during application loading time.

public class Singleton {
 /*
  * Initializing the static member variable as null
  */
 public static Singleton single = null;

 /*
  * private means, we can not create an object using a new operator outside
  * this class
  */
 private Singleton() {

 }

 /*
  * This method always returns the same instance. you can make this method as
  * synchronized to create a multiple instances by different thread at a time
  */

 public static Singleton getInstance() {
  if (single == null) {
   single = new Singleton();
  }
  return single;
 }

 /*
  * clone is not supported and throws an exception if we make the clone of this
  * object
  *
  * @see java.lang.Object#clone()
  */
 public Object clone() throws CloneNotSupportedException {
  throw new CloneNotSupportedException(
    "This is singleton class, cloning is not supported");
 }

 public static void main(String args[]) {
  /*
   * calling the multiple getInstance methods always returns the same
   * instance
   */
  System.out.println("Object=1 " + getInstance());
  System.out.println("Object=2 " + getInstance());
 }
}

Lazy Initialization singleton example

The singleton class is generated and initialized lazily in this case, signifying that the creation of a single object occurs only when the client calls the getInstance method.

With this approach, the Singleton instance is not created during application startup but is generated only when needed.

This approach is particularly useful in the following scenarios:

  • When instance creation is resource-intensive.
  • When the Singleton instance is not needed during application startup.
  • It helps reduce the loading time of the application.
  • There is a minimal delay for the initial instance creation.
public class SingletonClass {

    private static class Loader {
        static SingletonClass object = new SingletonClass();
    }

    private SingletonClass () {}

    public static SingletonClass getInstance() {
        return Loader.object;
    }
}

All the above examples, returns a single instance per thread, Then how to create a single object in multi-threaded applications.

Singleton thread-safe example

When running your application in a multi-threaded environment, it’s crucial to ensure that only a single instance of a class is created, making it thread-safe as a singleton. To achieve this, you can employ the synchronized keyword.

The synchronized keyword is particularly relevant and named in the context of multi-threaded applications. When a thread enters the synchronized block, it acquires a lock, causing another thread to wait until the first thread completes its task.

By implementing this mechanism, we can guarantee that a single object is created even when multiple threads attempt to access the instance creation process concurrently.

public class Singleton {

private static Singleton instance = null;
privat e Singleton() {}

public static Singleton getInstance() {
        if (instance == null) {
                synchronized (Singleton.class) {
                        if (instance == null) {
                                instance = new Singleton();
                        }
                }
        }
        return instance;
}

Advantage

The Singleton design pattern maintains a single instance of a Java object in the heap memory of the Java Virtual Machine, reducing the number of created objects and improving performance.