Singleton means only one instance of a class can exist in the system at any given time.
Four points to keep in mind when creating a Singleton:
- Make the contructor private (to control the instance creation)
- Add a static method that creates only one instance of the class
- Add a static variable to hold the instance
- Make the class final (so that there are no child classes)
You can use any of the below ways to create a Singleton:
A. Easy way (not thread-safe):
public final class Singleton {
private static Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
Problem with this is that it is not thread-safe. So, you can’t guarantee a single instance all the time.
B. Adding synchronized
keyword to the above method to make it thread-safe:
public final class Singleton {
private static volatile Singleton instance;
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton .class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
C. Using a static variable:
public final class Singleton {
private static final Singleton INSTANCE = new Singleton();
public static Singleton getInstance() {
return INSTANCE;
}
}
This leverages the fact that static fields and blocks are initialized one after another. See Java Language Specification 12.4.2 to learn more.
D. Using a static class (Lazy Initialization):
public final class Singleton {
private static class InstanceWrapper {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return InstanceWrapper.INSTANCE;
}
}
Java Language Specification 12.4.2 says that a class isn’t initialized unless we access one of its method or field. Ergo, in this case, unless we call getInstance()
, InstanceWrapper
won’t be initialized and the instance won’t be created. Basically, this is an improvement to our previous approach.
E. Using Enum (Concept taken from Effective Java Book by Joshua Block):
public enum EnumSingleton {
INSTANCE;
private EnumSingleton() { }
public EnumSingleton getInstance() {
return INSTANCE;
}
// getters and setters...
}
Usage:
EnumSingleton enumSingleton = EnumSingleton.INSTANCE.getInstance();
This approach is both serializable as well as thread-safe.