Core Java

Singleton Class in Java Design Pattern – Best Practices with Examples

Photo of YatinYatinJuly 19th, 2018Last Updated: May 18th, 2020
2 956 10 minutes read

In this post, we feature a comprehensive Tutorial on Singleton Class in Java.Design Patterns in Java are incredibly popular among the software developers. One of the most common interview questions is theSingleton Design Pattern. So in this tutorial, I’ll summarize the best practices which will help developers dodge general issues and develop better applications.

1. What are Design Patterns?

Adesign pattern is known as a well-proven solution to a commonly occurring problem in the software design. They can speed up the development process by providing the tested and proven development paradigms. Using design patterns offer few advantages such as:

  • Reusable in multiple projects
  • Provide solutions for an effective system architecture
  • Provide clarity and transparency to the application design
  • Provide robust and highly maintainable code for easy understanding and debug

Java has several design patterns and the Singleton Pattern is the most commonly used.

1.1 What is Java Singleton Design Pattern?

  • The Singleton pattern is a part of Creational design patterns
  • In Java, thenew keyword creates an instance of a class whenever required. But there are some cases where developers need to have an isolated instance of a class such as:
    • A single database connection object
    • A single shared resource
  • Therefore, this design pattern ensures that onlyone instance of a given class is created and a global access to that instance is provided
Singleton Class in Java - Classic Singleton Design Pattern
Fig. 1: Classic Singleton Design Pattern

1.2 Pre-requisites

To implement the this design pattern in the Java programming language, developers need to have the following:

  • Static Member: It will create a single instance in the JVM memory asstatic are class level variables.
  • Private Constructor: It will restrict the instantiation of the Singleton class from the outside world (i.e. Initialization of this class using thenew keyword is prevented)
  • Static factory method: This provides the global point of access to the Singleton object and returns the instance to the caller

1.3 Structure

In the Java programming language, there are different implementations of the singleton pattern. But before we start, the singleton design pattern should be consideredonly if all the three criteria’s are satisfied i.e.

  • Ownership of the single instance cannot be changed
  • Lazy initialization is recommended
  • Global access to the singleton instance is not otherwise provided

Over here is the classic implementation of the Singleton Design Pattern.

SingletonClassDemo.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
packagecom.java.design.pattern.singleton;
 
// Lazy Initialization
publicclassSingletonClassDemo {
 
    // Static attribute.
    privatestaticSingletonClassDemo instance =null;
 
    // Private constructor.
    privateSingletonClassDemo() {
 
    }
 
    // Static function.
    publicstaticSingletonClassDemo getInstance() {
        // If there is no instance available, create new one (i.e. lazy initialization).
        if(instance ==null) {
            instance =newSingletonClassDemo();
        }
        returninstance;
    }
}

In the preceding example, we wrote a class with a method that creates a new instance of the class if one does not exist. Do note:

  • Theinstance attribute in the class is definedprivate andstatic
  • The constructor of the class is madeprivate so that there is no other way to instantiate the class
  • The accessor function for obtaining the reference to the singleton object is definedpublic andstatic

This example is known asLazy Initialization – which means that it restricts the instance creation until it is requested for the first time.

1.4 Real-time examples

Here represent some significant scenarios where the singleton design pattern is used.

  • The singleton pattern is used in the logger classes. These classes provide a global logging access point in all the application components without being necessary to produce an object each time a logging operation is performed
  • The singleton pattern is used to design the classes which provide the configuration settings for an application. This approach provides a global access point and keeps the instance as a cache object
  • The singleton pattern is used to design the application that needs to work with the serial port
  • The singleton pattern can be used with Abstract Factory, Builder, and Prototype design patterns to have a unique object

Note: If a Singleton class is loaded by two classloaders, two instances of the Singleton class will be created (i.e. one for each classloader).

2. Java Singleton Design Pattern Best Practices

In this section, we will explore the strategies that can be adopted to improve the Singleton design pattern.

2.1 Eager Initialization

In eager initialization, the instance of the singleton class is created at the time of class loading. This approach offers the easiest execution and helps improve the runtime performance of the application. Here is an example ofEager Initialization singleton class.

SingletonClassDemo2.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
packagecom.java.design.pattern.singleton;
 
// Eager Initialization
publicclassSingletonClassDemo2 {
 
    // Static attribute.
    // Making the "instance" attribute as "final" ensures that only one instance of the class exists.
    privatestaticfinalSingletonClassDemo2 instance =newSingletonClassDemo2();
 
    // Private constructor.
    privateSingletonClassDemo2() {
 
    }
 
    // Static function.
    publicstaticSingletonClassDemo2 getInstance() {
        returninstance;
    }
}

This approach is similar to lazy initialization, but it has a drawback i.e. the instance is always created even though the application is not utilizing it. This is considered a destructive practice for creating the database connections or sockets as it may lead to memory leak problems.

2.1.1 Static Initialization

The implementation ofstatic block initialization is similar to the eager initialization, except that instance of the class is created in astatic block that provides an option for the exception handling.

1
2
3
4
5
6
7
8
// Static block initialization for exception handling.
static{
    try{
        instance =newStaticSingletonClassDemo();
    }catch(Exception ex) {
        thrownewRuntimeException("Exception occurred in creating the singleton instance ...!");
    }
}

2.2 Bill Pugh Singleton

Prior to Java 5, Java memory model had many issues and the developers had to use the Bill Pugh Solution for implementing the Single design pattern in their applications. This approach is based oninitialization on demand idiom and uses the Inner classes’ concept. Here is an example ofBill Pugh Solution singleton class.

SingletonBillPughDemo.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
packagecom.java.design.pattern.singleton;
 
publicclassSingletonBillPughDemo {
 
    // Private constructor.
    privateSingletonBillPughDemo() {
 
    }
 
    // Static inner class.
    privatestaticclassLazyholder {
        // Static attribute.
        privatestaticfinalSingletonBillPughDemo INSTANCE =newSingletonBillPughDemo();
    }
 
    // Static function.
    publicstaticSingletonBillPughDemo getInstance() {
        returnLazyholder.INSTANCE;
    }
}

To a degree, Bill Pugh Singleton has been the good approach, but it is easily destroyed through the Java Reflection API. Hence, this approached was not heartily recommended by the Java developers.

2.3 Using Enum

Enum was introduced in Java 5 and provides a thread-safe implementation. The objects returned by Enum are Singleton in nature and therefore can be effectively used for implementing the Singleton design pattern in the multi-threaded environment.

SingletonEnum.java

1
2
3
4
5
6
7
packagecom.java.design.pattern.singleton;
 
publicenumSingletonEnum {
    INSTANCE;
}
 
// The singleton instance can be accessed via "SingletonEnum.INSTANCE".

This approach is easy but it has 2 drawbacks i.e.

  • Enum does not support the lazy initialization
  • Changing the Singleton class to Multi-ton is not possible with Enum

2.4 Thread-Safe Singleton

Consider a scenario if two threads try to create an instance of a singleton class at the same time. In a multi-threaded environment, there is a possibility that separate objects get created, due to different times of accessing the(instance == null) check. This will break the singleton principle. The simplest way of achieving the thread safety in the singleton design pattern is to make thegetInstance() method synchronized.

Here is an example of theThread-Safe singleton class.

SingletonClassDemo3.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
packagecom.java.design.pattern.singleton;
 
// Thread-Safe Implementation
publicclassSingletonClassDemo3 {
 
    // Static attribute.
    privatestaticSingletonClassDemo3 instance =null;
 
    // Private constructor.
    privateSingletonClassDemo3() {
 
    }
 
    // Static function.
    // Only one thread can execute this at a time.
    publicstaticsynchronizedSingletonClassDemo3 getInstance() {
        // If there is no instance available, create new one (i.e. lazy initialization).
        if(instance ==null) {
            instance =newSingletonClassDemo3();
        }
        returninstance;
    }
}

At this location using thesynchronized keyword will ensure thread-safety but the application performance will be degraded. So at one side, we are resolving the problem on another side we are creating one more. To solve this,Double Check Lock principle is used.

2.5 Double Check Locking Principle

The locking mechanism in the singleton design pattern causes the thread to get a lock on thegetInstance method only when the instance isnull. This prevents the unnecessary synchronization once the instance variable is initialized. Here is an example of aDouble Check Locking singleton class.

SingletonClassDemo4.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
packagecom.java.design.pattern.singleton;
 
// Double Check Locking Principle
publicclassSingletonClassDemo4 {
 
    // Static attribute.
    privatestaticSingletonClassDemo4 instance =null;
 
    // Private constructor.
    privateSingletonClassDemo4() {
 
    }
 
    // Static function.
    publicstaticSingletonClassDemo4 getInstance() {
        // Double check locking principle.
        // If there is no instance available, create new one (i.e. lazy initialization).
        if(instance ==null) {
 
            // To provide thread-safe implementation.
            synchronized(SingletonClassDemo4.class) {
 
                // Check again as multiple threads can reach above step.
                if(instance ==null) {
                    instance =newSingletonClassDemo4();
                }
            }
        }
        returninstance;
    }
}

2.6 Using Volatile Keyword

At this point, the singleton implementation looks perfect. But it will still be incomplete without the use of thevolatile keyword. This keyword guarantees thehappens-before relationship i.e. all the write will happen in the volatile instance before any read of the instance.

Want to be a Java Master ?
Subscribe to our newsletter and download the JavaDesignPatternsright now!
In order to help you master the Java programming language, we have compiled a kick-ass guide with all the must-know Design Patterns for Java! Besides studying them online you may download the eBook in PDF format!

Thank you!

We will contact you soon.

SingletonClassDemo5.java

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
packagecom.java.design.pattern.singleton;
 
// Double Check Locking Principle
publicclassSingletonClassDemo5 {
 
    // Static and Volatile attribute.
    privatestaticvolatileSingletonClassDemo5 instance =null;
 
    // Private constructor.
    privateSingletonClassDemo5() {
 
    }
 
    // Static function.
    publicstaticSingletonClassDemo5 getInstance() {
        // Double check locking principle.
        // If there is no instance available, create new one (i.e. lazy initialization).
        if(instance ==null) {
 
            // To provide thread-safe implementation.
            synchronized(SingletonClassDemo5.class) {
 
                // Check again as multiple threads can reach above step.
                if(instance ==null) {
                    instance =newSingletonClassDemo5();
                }
            }
        }
        returninstance;
    }
}

Up till now, these have been the most widely used approaches for the Singleton design pattern. I am using5th and the6th approach in many of my projects as it is easy to understand and implement in the multi-threaded environment.

3. Ways to Kill Singleton

In this section, we will discuss three essential concepts which can break the singleton property of a class and how to prevent them. Let’s discuss them one by one.

3.1 Reflection

Reflection can easily destroy the Singleton design of a class by calling the private constructor and setting the access level totrue. Let’s understand this with the help of a code snippet:

01
02
03
04
05
06
07
08
09
10
11
12
try{
    Constructor[] constructors = Singleton.class.getDeclaredConstructors();
    for(Constructor constructor : constructors) {
                 
        // Below Code Will Destroy the Singleton Pattern
        constructor.setAccessible(true);
        instanceTwo = (Singleton) constructor.newInstance();
        break;
    }
}catch(Exception ex) {
    ex.printStackTrace();
}

To overcome this, Enum is used because JVM ensures that the Enum value is instantiated only once and the objects returned by Enum are Singleton in nature. The purpose of using Enum is that its default constructor is private in nature and developers cannot invoke them through the program. Its only drawback is it does not allow the Lazy initialization for the Singleton design pattern.

3.2 Serialization

In distributed systems, the Singleton design can be destroyed during the deserialization process as it’ll create a new instance of the Singleton class. To overcome this issue, developers have to implement thereadResolve() method in the Singleton class implementing theSerializable interface. Let’s understand this with the help of a code snippet:

1
2
3
4
// Implementing the 'readResolve()' method.
protectedObject readResolve() {
    returngetInstance();
}

3.3 Cloning

Cloning is a concept where one can produce the copy of an instance and therefore destroying the Singleton design of a class. To overcome this issue, developers have to override theclone() method and throw theCloneNotSupportedException exception from that method. Let’s understand this with the help of a code snippet:

1
2
3
4
@Override
protectedObject clone()throwsCloneNotSupportedException {
    thrownewCloneNotSupportedException();
}

4. Conclusion

These tips and examples on theSingleton Design Pattern are based on my experience and how I use this design pattern in the Java programming language.

4.1 Thumb Rules

  • Abstract Factory, Builder, Façade, and Prototype design patterns can use the Singleton in their implementation
  • Implement the double locking principle in the singleton design pattern to ensure thread-safety in the application
  • Beware of the object cloning as it can break your singleton. Remember restricting the object’sclone() method
  • Beware of the Java Reflection API as it can again break your singleton. Throw the runtime exception in the constructor if the(instance != null) check is true
  • Make the singleton class safe from Serialization
  • java.lang.Runtime andjava.awt.Desktop are the two Singleton classes provided by the JVM

That’s all for this tutorial and I hope the article served you whatever you were looking for. Happy Learning and don’t forget to share!

5. Download the Eclipse Project

This was an example of following the best practices in the Java Singleton Design Pattern.

Download
You can download the full source code of this example here:Singleton Class in Java Design Pattern – Best Practices with Examples
Do you want to know how to develop your skillset to become aJava Rockstar?
Subscribe to our newsletter to start Rockingright now!
To get you started we give you our best selling eBooks forFREE!
1. JPA Mini Book
2. JVM Troubleshooting Guide
3. JUnit Tutorial for Unit Testing
4. Java Annotations Tutorial
5. Java Interview Questions
6. Spring Interview Questions
7. Android UI Design
and many more ....
I agree to theTerms andPrivacy Policy

Thank you!

We will contact you soon.

Photo of YatinYatinJuly 19th, 2018Last Updated: May 18th, 2020
2 956 10 minutes read
Photo of Yatin

Yatin

An experience full-stack engineer well versed with Core Java, Spring/Springboot, MVC, Security, AOP, Frontend (Angular & React), and cloud technologies (such as AWS, GCP, Jenkins, Docker, K8).

Related Articles

Bipartite Graph

Java not equal Example

January 17th, 2020
Bipartite Graph

Java API Tutorial

October 26th, 2020
Bipartite Graph

Java Struct Example

January 8th, 2020
Bipartite Graph

Java Node Example

November 20th, 2019
Bipartite Graph

Java Swing MVC Example

January 26th, 2016
Bipartite Graph

How to call a method in Java

December 26th, 2019
Subscribe
Notify of
guest
I agree to theTerms andPrivacy Policy
The comment form collects your name, email and content to allow us keep track of the comments placed on the website. Please read and accept our website Terms and Privacy Policy to post a comment.

I agree to theTerms andPrivacy Policy
The comment form collects your name, email and content to allow us keep track of the comments placed on the website. Please read and accept our website Terms and Privacy Policy to post a comment.