Fundamentals 14 min read

Double‑Checked Locking, Static Inner Class, and Enum Singleton Implementations in Java

This article explains three Java singleton implementations—double‑checked locking with volatile, static inner‑class holder, and enum singleton—detailing their thread‑safety, lazy initialization, and how they prevent issues such as instruction reordering, serialization, and reflection attacks.

Selected Java Interview Questions
Selected Java Interview Questions
Selected Java Interview Questions
Double‑Checked Locking, Static Inner Class, and Enum Singleton Implementations in Java

1. Double‑Checked Locking (DCL) Singleton

The DCL pattern provides thread‑safe lazy initialization by checking the instance twice, once without synchronization and once inside a synchronized block, and requires the instance variable to be declared volatile to prevent instruction reordering.

public class Singleton {
    private static volatile Singleton singleton;
    private Singleton() {}
    public static Singleton getInstance() {
        if (singleton == null) {
            synchronized (Singleton.class) {
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}

Without the second check, two threads could create separate instances. The volatile keyword ensures that the write to singleton is visible to other threads and prevents the JVM from reordering the object construction steps.

Why double check?

If two threads enter getInstance() simultaneously, the first thread creates the instance inside the synchronized block; without the second if , the second thread would also create a new instance after the lock is released, breaking the singleton guarantee.

Why volatile ?

Object creation involves three steps: memory allocation, constructor execution, and assigning the reference. Without volatile , the last two steps can be reordered, leading to a partially constructed object being observed by other threads. Since JDK 1.5, volatile prevents this reordering.

2. Static Inner‑Class Singleton

This approach leverages the class‑loading mechanism: the inner static class holds the singleton instance, which is created only when the outer class's getInstance() method is called.

public class Singleton {
    private Singleton() {}
    private static class SingletonInstance {
        private static final Singleton singleton = new Singleton();
    }
    public static Singleton getInstance() {
        return SingletonInstance.singleton;
    }
}

It offers lazy loading and high efficiency similar to DCL, but like DCL it cannot prevent multiple instances caused by serialization or reflection.

3. Enum Singleton (Recommended)

Enum singletons are inherently thread‑safe, handle lazy initialization automatically, and protect against serialization and reflection attacks because the JVM ensures a single enum instance.

public enum Singleton {
    INSTANCE;
    public void testMethod() {
        // method body
    }
}

During serialization, only the enum name is written, and deserialization uses java.lang.Enum.valueOf to retrieve the existing instance, avoiding a new object. Reflection cannot instantiate an enum and throws java.lang.IllegalArgumentException: Cannot reflectively create enum objects .

Usage Example

// Singleton.java
public enum Singleton {
    INSTANCE;
    public void testMethod() {
        System.out.println("Executed singleton method");
    }
}

// Test.java
public class Test {
    public static void main(String[] args) {
        Singleton.INSTANCE.testMethod();
        System.out.println(Singleton.INSTANCE);
    }
}

Running the program prints the method message and the enum instance.

Decompiling the Enum Singleton

Decompiling with javap -p Singleton.class reveals that the enum defines a static field INSTANCE , a private static array $VALUES , and a static initializer that creates the instance. The static block contains bytecode instructions such as new , dup , invokespecial , and putstatic to instantiate and assign the enum constant, ensuring thread‑safety at class‑loading time.

public final class Singleton extends java.lang.Enum
{
    public static final Singleton INSTANCE;
    private static final Singleton[] $VALUES;
    static {}
    // ... other generated methods (values, valueOf, etc.)
}

The static initializer creates the enum instance and populates the $VALUES array, guaranteeing that INSTANCE is constructed exactly once when the class is loaded.

In summary, while DCL and static inner‑class singletons provide lazy loading, the enum singleton is the most robust solution in Java because it automatically handles serialization, reflection, and thread‑safety without additional code.

Javaconcurrencyenumdesign patternvolatilesingleton
Selected Java Interview Questions
Written by

Selected Java Interview Questions

A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.