low-level-design3 min read

Singleton Design Pattern Tutorial from Scratch (2026)

Singleton Design Pattern Tutorial from Scratch (2026)

Published:  |  Category: Low Level Design  |  Reading time: ~15 min
Singleton Design Pattern Tutorial from Scratch (2026)

The Singleton pattern ensures a class has only one instance and provides a global point of access to it. It is one of the most commonly used creational patterns in object-oriented programming, particularly useful when exactly one object is needed to coordinate actions across a system.

In this comprehensive tutorial, you will learn how to implement Singleton in Java using eager initialization, lazy initialization with double-checked locking, thread-safe variants, and the modern enum approach. We will also explore real-world use cases such as logging, configuration management, connection pools, and cache managers.

Eager Initialization Singleton

Eager initialization creates the singleton instance at class loading time. This is the simplest approach but may waste resources if the instance is never used. It is inherently thread-safe because the JVM guarantees that static initializers are executed only once.

public class EagerSingleton {
    private static final EagerSingleton instance = new EagerSingleton();

    private EagerSingleton() {}

    public static EagerSingleton getInstance() {
        return instance;
    }

    public void showMessage() {
        System.out.println("Eager Singleton instance hash: " + hashCode());
    }
}

Lazy Initialization with Double-Checked Locking

Lazy initialization defers instance creation until the first call to getInstance(). The double-checked locking pattern reduces synchronization overhead by first checking the instance without synchronization, then acquiring a lock only if the instance is null.

The volatile keyword prevents instruction reordering issues that could cause half-initialized objects to be visible to other threads. This is the recommended approach for lazy thread-safe singletons in Java.

public class LazySingleton {
    private static volatile LazySingleton instance;

    private LazySingleton() {}

    public static LazySingleton getInstance() {
        if (instance == null) {
            synchronized (LazySingleton.class) {
                if (instance == null) {
                    instance = new LazySingleton();
                }
            }
        }
        return instance;
    }
}

Enum Singleton (Best Practice)

Joshua Bloch's Effective Java recommends using a single-element enum for implementing singletons. Enum singletons are inherently serialization-safe, provide protection against reflection attacks, and guarantee a single instance even in multi-threaded environments.

This approach is widely considered the best Java singleton pattern because it handles all the edge cases that other implementations must manually address.

public enum EnumSingleton {
    INSTANCE;

    private final String config = "default-config";

    public void execute() {
        System.out.println("Enum Singleton executing with config: " + config);
    }

    public String getConfig() {
        return config;
    }
}

// Usage
EnumSingleton.INSTANCE.execute();

Frequently Asked Questions

When should I use the Singleton pattern?

Use Singleton when you need exactly one instance of a class to coordinate actions across the system, such as logging, configuration management, thread pools, or caching. Avoid overusing it as it introduces global state and complicates unit testing.

Is Singleton an anti-pattern?

Singleton is sometimes considered an anti-pattern because it introduces global state, makes code tightly coupled, and complicates testing. However, it remains useful when applied judiciously for infrastructure concerns like logging or configuration where a single instance is genuinely required.

How do I make a Singleton thread-safe in Java?

Use the enum approach (best), eager initialization if the instance is always needed, or double-checked locking with a volatile field for lazy initialization. Avoid synchronized methods as they degrade performance.

Can a Singleton be serialized safely?

Yes, but you must implement the readResolve() method to return the existing instance, otherwise deserialization creates a new instance. The enum singleton handles this automatically.

Originally published on Ayodhyyya. Last updated June 1, 2026.