Singleton pattern is used to ensure that, only one instance of a class can be created.
NOTES
In this article, we are discussing the implementation of the Singleton Pattern in Java. Implementation of the Singleton pattern in Java follows the same steps as TypeScript and PHP.
See the Singleton in other languages in the “Other Code Implementations” section. Or, use the link below to check the details of the Singleton Pattern-
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:
Example | Source Code Link |
---|---|
Example #1: Database Connection | GitHub |
Other Code Implementations
Use the following links to check Singleton pattern implementation in other programming languages.