How to create Singleton Design Pattern in Java
java
design pattern
singleton
oop
enum
singleton java
singleton pattern
A design pattern is a general solution to a common problem. The singleton pattern is used to restricts the instantiation of a class to one single object.
To implement singleton pattern you need to provide the mechanism to create one object and possibility to be accessed globally (a public method).
There are several ways to implement the singleton pattern. The singleton pattern can cause problems in multi-threaded applications , that's why needed extra attention. If two threads are going to execute the creation method at the same time when a singleton does not yet exist, they both must check for an instance of the singleton and then only one should create the new one.
Method 1 - Lazy initialization
The lazy initialization will create the singleton object only if is necessary.
public class SingletonLazy1 {
private static volatile SingletonLazy1 instance;
private String name = null;
private SingletonLazy1() {
this.name = "Singleton pattern - lazy implementation, method 1.";
}
public static SingletonLazy1 getInstance() {
if (instance == null ) {
synchronized (SingletonLazy1.class) {
if (instance == null) {
instance = new SingletonLazy1();
}
}
}
return instance;
}
public String getName() {
return this.name;
}
}
This method would be the most tread-safe method to create the singleton pattern. The volatile object and synchronized block will ensure that only one instance will be created.
If the system will be a low concurrency multi-thread application then this solution can be simplified using a synchronized method.
public class SingletonLazy2 {
private static SingletonLazy2 instance;
private String name = null;
private SingletonLazy2() {
this.name = "Singleton pattern - lazy implementation, method 2.";
}
public static synchronized SingletonLazy2 getInstance() {
if (instance == null) {
instance = new SingletonLazy2();
}
return instance;
}
public String getName() {
return this.name;
}
}
Method 2 - Eager initialization
If the application will always need the object, or if the of creating costs the object is low, then the object can be created at application startup.
public class SingletonEager {
private static final SingletonEager INSTANCE = new SingletonEager();
private String name = null;
private SingletonEager() {
this.name = "Singleton pattern - eager implementation.";
}
public static SingletonEager getInstance() {
return INSTANCE;
}
public String getName() {
return this.name;
}
}
The advantage for eager initialization method is that the static initializer for INSTANCE object is run when the class is initialized, after class loading but before the class is used by any thread, so no need for synchronized method/block or null check.
Method 3 - Static block initialization
The static block initialization is similar with eager initialization with the advantage that you can check and treat the errors during the initialization.
public class SingletonStaticBlock {
private static final SingletonStaticBlock INSTANCE;
static {
try {
INSTANCE = new SingletonStaticBlock();
} catch (Exception e) {
throw new RuntimeException("An error occurred!", e);
}
}
private String name = null;
private SingletonStaticBlock() {
this.name = "Singleton pattern - static block implementation.";
}
public static SingletonStaticBlock getInstance() {
return INSTANCE;
}
public String getName() {
return this.name;
}
}
Method 4 - Using enum
This enum approach implements the singleton by taking advantage of Java's guarantee that any enum value is instantiated only once in a Java program.
public enum SingletonEnum {
INSTANCE;
private String name;
private SingletonEnum() {
this.name = "Singleton pattern - enum implementation.";
}
public String getName () {
return this.name;
}
}
Testing
public class App {
public static void main(String[] args) {
System.out.println("Testing singleton pattern");
System.out.println(SingletonLazy1.getInstance().getName());
System.out.println(SingletonLazy2.getInstance().getName());
System.out.println(SingletonEager.getInstance().getName());
System.out.println(SingletonStaticBlock.getInstance().getName());
System.out.println(SingletonEnum.INSTANCE.getName());
}
}
Output
Testing singleton pattern
Singleton pattern - lazy implementation, method 1.
Singleton pattern - lazy implementation, method 2.
Singleton pattern - eager implementation.
Singleton pattern - static block implementation.
Singleton pattern - enum implementation.