Java Singleton Pattern Implementation

There are several different ways to implement the Java singleton pattern.

  1. 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;
    }
}
  1. 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.

  1. 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.

  1. 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.

  1. 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
    }
}
bannerAds