Design Pattern: Singleton Pattern in Java

Singleton pattern is used to ensure that, only one instance of a class can be created.

This article demonstrates Singleton pattern implementations in Java. Check the following examples.

Implementation

There are multiple approaches we can take to implement Singleton Pattern in Java. All the implementation methods are mostly the same, just with some small differences.

Common Key Points

In all the approaches few rules will be mostly the same.

  • Use a private static variable to store the instance of Singleton class (in the same class).
  • Make the constructor private, to restrict direct access from the client(using new).
  • Use a static method to create and return a new instance, or return an existing instance(if any).

Let’s take a look at the different methods of implementing Singleton pattern.

Method #1: Lazy Initialization

This is the simplest approach we can take to implement Singleton pattern. Check if there is any existing instance – if not there generate a new instance and return, else return the existing instance.

// Singleton implemenation in Lazy initialization

public class Singleton {

    private static Singleton singletonInstance;

    private Singleton() {
    
    }

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

    // some utility methodes here
}

Here are a few key factors of this approach.

  • This approach is not thread-safe.
  • If more than one thread tries to generate a new instance at the same time, there is a possibility that those threads will get different instances of the Singleton class.

Method #2: Synchronized (Thread-Safe)

To make the Singleton implementation thread-safe, we can use the synchronized keyword for getInstance() method. This way only one thread will be able to use the getInstance() method at a time.

// Singleton implemenation in Synchronized

public class Singleton {

    private static Singleton singletonInstance;

    private Singleton() {
    
    }

    // Use synchronized for this method to make is thread-safe
    public static synchronized Singleton getInstance() {
        if (singletonInstance == null) {
            singletonInstance = new Singleton();
        }

        return singletonInstance;
    }

    // some utility methodes here
}

Here are a few key factors of this approach.

  • This approach is thread-safe.
  • Can cause performance issues if abused while using this approach. As all the threads have to wait to use the getInstance() method when one thread is already using it. Also the synchronized keyword is effective only the first time, once an instance is created then all threads will get that.

Method #3: Double-Checked Locking

This approach uses a synchronized block inside the if condition in the getInstance() method. So the code first checks if the instance exists, if not, then the synchronized is used. So synchronization is used while creating the instance for the first time.

Also, use the volatile keyword is used for the Singleton instance variable, to make sure that multiple threads handle the static variable properly.

// Singleton implemenation using Double-Checked Locking

public class Singleton {

    // Use volatile 
    private volatile static Singleton singletonInstance;

    private Singleton() {
    
    }

    public static Singleton getInstance() {
        if (singletonInstance == null) {
            // Use synchronized only when we need to create a new instance
            synchronized(Singleton.class) {
                if (singletonInstance == null) {
                    singletonInstance = new Singleton();
                }
            }
        }
        
        return singletonInstance;
    }

    // some utility methodes here
}

Here are a few key factors of this approach.

  • This approach is thread-safe.
  • Performance is better than the synchronized approach (Method #2)

Method #4: Eager Initialization

Very easy method for implementing Singleton. Just create a new instance and assign it to the singleton instance when the instance variable is declared.

// Singleton implemenation in Eager initialization

public class Singleton {

    // Assign a new instance while declaring the variable 
    private static Singleton singletonInstance = new Singleton();

    private Singleton() {
    
    }

    public static Singleton getInstance() {
        // Just return the instance here as it is already created   
        return singletonInstance;
    }

    // some utility methodes here
}

Use this approach if the Singleton class is not using lots of resources, as eager initialization will not wait for the getInstance() method call. The instance will be generated when the class is accessed for the first time.

Here are a few key factors of this approach.

  • This approach is thread-safe.
  • Uses fewer resources.
  • Does not matter if the client uses the singleton instance or not, the instance will be created.
  • The instance will be created before any thread access the singleton instance.

Method #5: Bill Pugh Approach

This is the standard & preferred method for Singleton pattern implementation in java.

This approach uses a helper class, which is an inner static class inside the singleton class. This helper class has the singleton instance variable declared, and also initialized with new Singleton().

// Singleton implemenation in Bill Pugh approach

public class Singleton {

    // Do not declare the static variable for instance

    private Singleton() {
    
    }

    private static class SingletonHelper {
        // Declare and initialize the variable for singleton instance
        public static final Singleton singletonInstance = new Singleton(); 
    }

    public static Singleton getInstance() {
       return SingletonHelper.singletonInstance;
    }

    // some utility methodes here
}

Here are a few key factors of this approach.

  • This approach is thread-safe.
  • Performs better than other approaches.
  • Singleton instance is created only if the client requests.

Examples

Let’s take a look at a few examples of Singleton Pattern.

Example #1: Database Connection

Let’s take the example of creating a class for database connection. Take a look at the class diagram.

Singleton Class

Here we have declared a Singleton class named “DbConnectionSingleton”. Here are the key points in this class:

  • A static variable is declared named “dbInstance”, this is of type of the same class(DbConnectionSingleton). So it will hold an instance of the “DbConnectionSingleton” class.
  • The constructor needs to be private, so we can not create an instance directly.
  • A static method is declared named “getInstance()”. If an instance already exists in the dbInstance variable, then return that, else create a new instance and return that.
// DbConnectionSingleton.java

package com.bigboxcode.designpattern.singleton.dbconnection;

public final class DbConnectionSingleton {

    private static DbConnectionSingleton dbInstance;
    private String url;
    private String port;
    private String username;
    private String password;

    private DbConnectionSingleton(String url, String port, String username, String password) {
        this.url = url;
        this.port = port;
        this.username = username;
        this.password = password;
    }

    public static DbConnectionSingleton getInstance(String url, String port, String username, String password) {
        if (dbInstance == null) {
            dbInstance = new DbConnectionSingleton(url, port, username, password);
        }
        return dbInstance;
    }

    public void printConnectionDetails() {
        System.out.println("URL:" + url);
        System.out.println("Port:" + port);
        System.out.println("User name:" + username);
        System.out.println("Password:" + password);
    }

    public void executeQuery(String query) {
        System.out.println("Executing query: " + query);
    }
}

Demo

This is the demo class which has the main method. In the main method, we have created an instance of the “DbConnectionSingleton” by using the “getInstance()” method (and passing correct params).

The second time we are trying to create another instance, by passing different parameters. But the getInstance() method does not create a new instance, and returns the object created in the previous step.

// Demo.java

package com.bigboxcode.designpattern.singleton.dbconnection;

public class Demo {
    private static final String DB_URL = "localhost";
    private static final String DB_PORT = "5432";
    private static final String DB_USERNAME = "postgres";
    private static final String DB_PASSWORD = "secret*pass";

    private static final String DB_URL2 = "192.168.55.55";
    private static final String DB_PORT2 = "1234";
    private static final String DB_USERNAME2 = "postgres2";
    private static final String DB_PASSWORD2 = "secret*pass2";

    public static void main(String[] args) {
        DbConnectionSingleton dbConnection = DbConnectionSingleton.getInstance(DB_URL, DB_PORT, DB_USERNAME, DB_PASSWORD);
        System.out.println("First Connection Details:");
        dbConnection.printConnectionDetails();

        DbConnectionSingleton secondDbConnection = DbConnectionSingleton.getInstance(DB_URL2, DB_PORT2, DB_USERNAME2, DB_PASSWORD2);
        System.out.println("\n\nSecond Connection Details:");
        secondDbConnection.printConnectionDetails();
    }
}

Output

Here is the output generated from the above demo.

First Connection Details:
URL: localhost
Port: 5432
User name: postgres
Password: secret*pass


Second Connection Details:
URL: localhost
Port: 5432
User name: postgres
Password: secret*pass

Source Code

Use the following link to get the source code:

Other Code Implementations

Use the following links to check Singleton pattern implementation in other programming languages.

Leave a Comment


The reCAPTCHA verification period has expired. Please reload the page.