Java Singleton Pattern Implementation
There are several different ways to implement the Java singleton pattern.
- Lazy Initialization:
creating an instance only when it is first used. One version of the lazy initialization implementation that is not thread safe is as follows:
public class Singleton {
private static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
Adding the “synchronized” keyword to the getInstance() method can achieve thread safety in lazy initialization singleton pattern, but it may impact efficiency.
public class Singleton {
private static Singleton instance;
private Singleton(){}
public static synchronized Singleton getInstance(){
if(instance == null){
instance = new Singleton();
}
return instance;
}
}
- Eager Initialization:
An instance is created during class loading, ensuring thread safety. The implementation is as follows:
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return instance;
}
}
It is not possible to achieve lazy loading because the instance is created during class loading.
- Double Checked Locking:
Building upon the lazy initialization pattern, double checked locking ensures both thread safety and efficiency.
public class Singleton {
private volatile static Singleton instance;
private Singleton(){}
public static Singleton getInstance(){
if(instance == null){
synchronized (Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
Using the `volatile` modifier for an instance variable can ensure visibility and ordering in a multi-threaded environment.
- Static Inner Class:
Using the static inner class of a class to achieve lazy loading and thread safety of a Singleton.
public class Singleton {
private Singleton(){}
private static class SingletonHolder{
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance(){
return SingletonHolder.INSTANCE;
}
}
Static inner classes are only loaded when they are first used, achieving lazy loading.
- Enumeration (Enum):
By utilizing an enumeration class to implement the Singleton pattern, it can ensure thread safety and prevent reflection attacks.
public enum Singleton {
INSTANCE;
public void doSomething(){
// do something
}
}