Pages

Friday, December 3, 2021

Java Singleton Design Pattern with Best Practices

1. Introduction


In this article, We'll learn what is singleton pattern is in java and how to implement it. You will learn various ways to create singleton objects. This is the only design pattern that is used by every application in the software industry and also used extensively in java API such as Spring, apache or spark, etc. A question from the design pattern is a must in the interview and many questions come from this topic. This is my favourite interview question that I ask software developers. This question will check to understand many areas of core java such as private access modifier, static members, cloning, multithreading, deep cloning, serialization and deserialization and reflection api.

    
                                    Java Singleton Design Pattern with Best Practices

In this post, You will learn the frequently asked question on the singleton design pattern. If you are preparing for interviews, this will give you a clear picture of the singleton pattern.


2. Singleton Design Pattern Rules


Sington means always one object should exist in the entire life of an application at any time. If a class produces two objects or more then it is not a singleton pattern.

Let us understand the rules for the singleton pattern.

  • First, need to make the constructor private so that object can not be created from any other class.
  • Create, Static field referencing the same class object.
  • Create a static method to get the singleton instance. This method will be invoked by other classes to get the singleton instance.


3. Singleton Design Pattern Creation

Creating a singleton class.

package com.java.w3schools.blog.java.program.to.desingpatterns;

public class SingletonPattern {

 // private static field.
 private static SingletonPattern instance;

 // private constructor
 private SingletonPattern() {

 }

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

  return instance;
 }

}

4. Singleton Design Pattern Verification


Created 3 singleton class objects in the below program. Printed all 3 objects and hashcodes as well. 


package com.java.w3schools.blog.java.program.to.desingpatterns;

public class SingletonPatternMain {

 public static void main(String[] args) {

  SingletonPattern object1 = SingletonPattern.getInstance();

  SingletonPattern object2 = SingletonPattern.getInstance();
  
  SingletonPattern object3 = SingletonPattern.getInstance();
  
  System.out.println("object 1 " + object1);
  System.out.println("object 2 " + object2);
  System.out.println("object 3 " + object3);

  System.out.println("object 1 hashCode " + object1.hashCode());
  System.out.println("object 2 hashCode " + object2.hashCode());
  System.out.println("object 3 hashCode " + object3.hashCode());
 }

}

Output:

Observe the output and all objects are having the same memory address and hashcodes. So, It is creating always single objects.

object 1 com.java.w3schools.blog.java.program.to.desingpatterns.SingletonPattern@4b1210ee
object 2 com.java.w3schools.blog.java.program.to.desingpatterns.SingletonPattern@4b1210ee
object 3 com.java.w3schools.blog.java.program.to.desingpatterns.SingletonPattern@4b1210ee
object 1 hashCode 1259475182
object 2 hashCode 1259475182
object 3 hashCode 1259475182

5. Singleton Design Pattern In Multiple threads


If the above code is used in concurrent applications there might be a chance of creating multiple objects. To avoid duplicate objects creation, object creation logic should be surrounded by some special monitor. This object creation logic is called a critical section and this should be synchronized.

5.1 Synchronizing Critical Section


public static SingletonPattern getInstance() {


  if (instance == null) {
  
   synchronized (SingletonPattern.class) {
    instance = new SingletonPattern();
   }
  }

  return instance;
 }
The above code is called single locking because only once if(instance == null) is checked.

5.2 Double Checked Locking


The above code is still having the chance for multiple objects creation. To prevent this from multiple threads, double-checking logic should be used here.

 // double locking pattern.
 public static SingletonPattern getInstance() {
  if (instance == null) {
   synchronized (SingletonPattern.class) {
    if (instance == null) {
     instance = new SingletonPattern();
    }
   }

  }

  return instance;
 }

6. Creating Singleton with ENUM


Now, let us jump into another interesting way of creating singleton with Enum. This approach is safer from cloning, serialization and multiple threads.

public enum SingletonEnum {

 INSTANCE("enum singleton");

 private String state;

 private SingletonEnum(String state) {
        this.state = state;
    }

 public SingletonEnum getInstance() {
  return INSTANCE;
 }

 public String getState() {
  return state;
 }

 public void setState(String state) {
  this.state = state;
 }

}

Verification with Enum:


public enum SingletonEnum {

 INSTANCE("enum singleton");

 private String state;

 private SingletonEnum(String state) {
        this.state = state;
    }

 public SingletonEnum getInstance() {
  return INSTANCE;
 }

 public String getState() {
  return state;
 }

 public void setState(String state) {
  this.state = state;
 }

}

Output:

enum singleton instance : enum singleton
enum singleton instance : enum singleton
enum singleton instance : enum singleton

7. Singleton Breaking With Cloning


This is an interview question. If Singleton class implements Clonable interface and implemented clone() then it returns a new object each time clone() method is called.

package com.java.w3schools.blog.java.program.to.desingpatterns;

public class SingletonPattern implements Cloneable{

 // common doublechecking logic or normal singel ton code.
 
 @Override
 protected Object clone() throws CloneNotSupportedException {
  // TODO Auto-generated method stub
  return super.clone();
 }

}

Let us check the hashcodes of cloned objects.


SingletonPattern object4 = SingletonPattern.getInstance();
System.out.println("Object 4 hashcode : " + object4.hashCode());

SingletonPattern object5 = (SingletonPattern) object4.clone();
System.out.println("Object 5 hashcode : " + object5.hashCode());

SingletonPattern object6 = (SingletonPattern) object4.clone();
System.out.println("Object 6 hashcode : " + object6.hashCode());

Output:

Object 4 hashcode : 1259475182
Object 5 hashcode : 1300109446
Object 6 hashcode : 1020371697

How to prevent singleton from cloning?


Answer 1: Return the same singleton instance from the clone method.

@Override
protected Object clone() throws CloneNotSupportedException {
 // TODO Auto-generated method stub
 return instance;
}

Answer 2: Throw exception saying clonenotsupportexception.

@Override
protected Object clone() throws CloneNotSupportedException {
 throw new CloneNotSupportedException("Clone not supported for SingletonPattern class");
}

Note: But recommended is not to implement the clonable interface in singleton pattern.

8. Singleton Breaking With Deep Cloning or serialization


How do you prevent singleton from creating another new instance from serialization?


This is a great interview question but you should have a deep understanding of serialization. During the serialization, readObject() method is used to create the object and return a new instance every time with readResolve() method.  To prevent creating a new object, just need to return the singleton instance from readResolve() method.

If you use Enum which is taken care of these by JVM.


9. Sington Breaking With Reflection API


How to prevent a singleton from creating another object from reflection api?

By using reflection api, We can change the constructor visibility to the public from private.

SingletonPattern object7 = SingletonPattern.getInstance();
System.out.println("Object 7 hashcode : " + object4.hashCode());

Constructor constructor = SingletonPattern.class.getDeclaredConstructor();
constructor.setAccessible(true);
SingletonPattern pattern = constructor.newInstance();
System.out.println("singeleton new object through reflection api : " + pattern.hashCode());

Output:

Object 4 hashcode : 1259475182
singeleton new object through reflection api : 1300109446

This can be avoided by throwing exceptions from the constructor if the singleton instance is not null.

 // private constructor
 private SingletonPattern() {

  if (instance != null) {
   throw new RuntimeException("You can create new object.");
  }

 }

10. Java API Singleton Classes



What are the Java built-in Singleton classes in Java API?


Runtime, Toolkit and Desktop classes are singleton classes.

Java.lang.Runtime with getRuntime()
Java.awt.Toolkit with getDefaultToolkit() 
Java.awt.Desktop with getDesktop()

11. Conclusion


In this article, we've seen what is singleton pattern and how to implement it? Frequently asked interview questions.

In conclusion, all examples are shown in this article are in GitHub


GitHub Code


No comments:

Post a Comment

Please do not add any spam links in the comments section.