CMD Guide
HomeOO & Low-Level DesignCreational

Singleton Pattern

What the Singleton Pattern Is

The Singleton pattern restricts a class to a single instance and gives the rest of the system one global access point to that instance. You reach for it when exactly one object must coordinate actions across a program — a configuration store, a logging facility, or a pool of expensive resources.

The mechanism is small. A static method checks whether the instance already exists. If it does not, the method creates it; if it does, the method returns the existing reference. Because the constructor is private, no other code can bypass this gate and create a second instance.

The problem it solves

When many clients each need a shared resource, naive code lets each client construct its own copy. If every client opened its own database connection, the server would be swamped and connection management would descend into chaos. Worse, separate instances drift into inconsistent state. The Singleton collapses all of those copies into one shared object that every client uses.

diagram
diagram

Structure

The pattern has two collaborators. SingletonObject enforces the single-instance rule and holds the shared state. SingletonDemo is any client that asks SingletonObject for the instance and then uses it.

SingletonObject

SingletonDemo

The demo class holds main(), the program entry point. It calls SingletonObject.getInstance() ("asks"), receives the shared instance back ("returns"), and invokes a method on it.

diagram
diagram

Implementation

Across languages the recipe is the same: make the constructor private so nobody can call new from outside, and expose a static method that hands back the cached instance. The version below is eager — the instance is built once when the class loads, stored in a final field, and simply returned on every call. Because the JVM guarantees class initialization happens once and in a thread-safe way, this variant is automatically safe under concurrency without any locking.

class SingletonObject {

  // Private static instance, eagerly initialized
  private static final SingletonObject instance = new SingletonObject();

  // Private constructor to prevent direct instantiation
  private SingletonObject() {}

  // Public method to get the sole instance of the class
  public static SingletonObject getInstance() {
    return instance;
  }

  // Method to display a message
  public void showMessage() {
    System.out.println("Hello from Singleton Pattern!");
  }
}

public class Solution {
  public static void main(String[] args) {
    // new SingletonObject(); // compile error: constructor is private
    SingletonObject object = SingletonObject.getInstance();
    object.showMessage();
  }
}

Trying to call new SingletonObject() from main would fail to compile — that is the private constructor doing its job. The only door in is getInstance().

Thread-safe lazy variants. The code above is eager: the instance is built when the class loads. If you need create-on-first-use instead, use the Bill Pugh singleton holder (a static nested class whose initializer runs only when referenced) or an enum. Double-checked locking (DCL) is the classic lazy + thread-safe attempt, but it is broken without volatile: instance = new Singleton() is three steps — allocate memory, run the constructor, then publish the reference into instance — and the compiler/JVM is permitted to reorder the last two (publish the reference before the constructor has finished), so a second thread reading instance outside the lock can see a non-null but partially-constructed object. volatile forbids that reordering and supplies the happens-before edge.

// BROKEN without volatile: a reader can see a half-built instance
private static Singleton instance;            // missing volatile

// FIXED:
private static volatile Singleton instance;
public static Singleton getInstance() {
    if (instance == null) {                   // 1st check, no lock
        synchronized (Singleton.class) {
            if (instance == null)             // 2nd check, locked
                instance = new Singleton();   // volatile publish
        }
    }
    return instance;
}

Prefer the Bill Pugh holder idiom or an enum — both get laziness and thread-safety without this subtlety.

Two ways a class-based Singleton is silently broken (and why enum is immune)

A private constructor stops new at compile time. But the JVM has two runtime back doors that bypass it entirely, each silently creating a second instance and breaking the one-instance guarantee. These are a top-3 senior-level Singleton interview probe.

Attack 1: Deserialization

When you serialize a singleton and deserialize it, ObjectInputStream.readObject() creates a brand-new instance by bypassing the constructor entirely (it uses internal JVM mechanisms, not new). The result: two objects in the same JVM that both believe they are the singleton.

// Demonstrate the deserialization attack
SingletonObject s1 = SingletonObject.getInstance();

ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("singleton.ser"));
out.writeObject(s1);
out.close();

ObjectInputStream in = new ObjectInputStream(new FileInputStream("singleton.ser"));
SingletonObject s2 = (SingletonObject) in.readObject();
in.close();

System.out.println(s1 == s2);  // false — two instances exist!

Defense: readResolve(). The Java serialization spec checks whether the deserialized class defines a readResolve() method. If it does, the return value of that method replaces the newly created object. So the singleton class adds:

// Inside SingletonObject — must implement Serializable
private Object readResolve() {
    return instance;  // discard the deserialized copy, return the real singleton
}

The deserialized duplicate is created momentarily but immediately discarded and garbage-collected. Every non-transient object field is also a hole: a crafted stream can capture a reference to the momentary pre-readResolve instance through such a field (Bloch’s “singleton stealer” attack, Effective Java Item 89), smuggling a second live reference that breaks the singleton. Make all instance fields transient — or prefer the enum singleton, which is immune.

Attack 2: Reflection

The Reflection API can make any constructor accessible at runtime, including private ones. A single call creates a second instance that completely bypasses getInstance():

// Demonstrate the reflection attack
SingletonObject s1 = SingletonObject.getInstance();

Constructor<SingletonObject> constructor =
    SingletonObject.class.getDeclaredConstructor();
constructor.setAccessible(true);           // bypass the private modifier
SingletonObject s2 = constructor.newInstance();

System.out.println(s1 == s2);  // false — two instances exist!

Defense: guard the constructor. The private constructor checks whether an instance already exists and throws if so. This turns the reflection path into a runtime error:

private SingletonObject() {
    if (instance != null) {
        throw new IllegalStateException(
            "Singleton already constructed — use getInstance()");
    }
}

This is a convention-level guard, not an airtight one — a determined attacker using sun.misc.Unsafe or manipulating the static field can still circumvent it. But it catches accidental misuse and makes the intent unmistakable.

Why enum is immune to both

An enum singleton is the recommendation from Joshua Bloch (Effective Java, Item 3) precisely because the JVM itself enforces singleton semantics at a level no class-based trick can match:

public enum DatabasePool {
    INSTANCE;

    private final HikariDataSource ds;

    DatabasePool() {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl("jdbc:postgresql://localhost/mydb");
        config.setMaximumPoolSize(10);
        ds = new HikariDataSource(config);
    }

    public Connection getConnection() throws SQLException {
        return ds.getConnection();
    }
}

// Usage — clean, safe, no getInstance() ceremony
Connection conn = DatabasePool.INSTANCE.getConnection();

The trade-off: when enum is NOT the answer

Enum singletons cannot extend a class (Java enums implicitly extend java.lang.Enum), so they are unsuitable when the singleton must inherit from a specific base class. They also do not support lazy initialization — the instance is created at class-loading time, period. If the singleton is expensive to construct and might never be used, the Bill Pugh holder idiom (lazy, class-based, thread-safe) is the better fit, guarded with readResolve() + the constructor check above.

VariantThread-safe?Lazy?Reflection-safe?Serialization-safe?Can extend a class?
Eager static finalYes (class init)NoNo (needs constructor guard)No (needs readResolve())Yes
Bill Pugh holderYes (class init of inner class)YesNo (needs constructor guard)No (needs readResolve())Yes
Double-checked lockingYes (with volatile)YesNo (needs constructor guard)No (needs readResolve())Yes
EnumYes (class init)NoYes (JVM-enforced)Yes (JVM-enforced)No

Where It Is Used

Configuration management. Settings load once at startup and stay consistent for the whole application lifecycle, with every part of the code reading from a single source.

Database connection pools. Rather than opening and closing connections constantly, a single pool object reuses a fixed set of connections, giving consistent, efficient access from anywhere in the app.

Hardware access management. For a printer or a graphics device, one coordinating object serializes access, prevents conflicts, and owns the initialization and shutdown routine.

Trade-offs

The Singleton's strengths and weaknesses are two sides of the same coin. The single global access point that makes it convenient is also a piece of hidden global state.

ProsCons
Controlled access — exactly one instance, reached through one well-known method.Global state — encourages shared mutable state that is hard to reason about and debug.
Thread-safe without extra locking — the eager, final form shown above relies on the JVM's one-time class initialization, so no synchronized or double-checked locking is needed.Testing friction — hard to mock or reset; state leaks across tests.
Shared-resource management — natural fit for pools, caches, and device handles.Tight coupling & hidden dependencies — callers depend on the global directly, so refactoring away from it touches every call site.

Singleton vs. Dependency Injection

The most common modern alternative is to create one instance and inject it wherever it is needed, rather than letting code reach out to a global accessor. Both give you a single shared object; the difference is who controls the wiring and how visible the dependency is.

DimensionClassic SingletonSingle instance via Dependency Injection
How callers get itCall a global getInstance() from anywhere.Receive it as a constructor or method parameter.
Dependency visibilityHidden — the dependency is buried inside method bodies.Explicit — it appears in the signature, so collaborators are obvious.
TestabilityHard to substitute a fake; shared state persists between tests.Easy to pass a mock or stub; each test wires its own instance.
Lifetime controlOwned by the class itself; one per process, hard to scope.Owned by the container/composition root; can be scoped per-request, per-thread, etc.
CostZero framework, almost no boilerplate — but the coupling tax is paid later, during testing and refactoring.Some upfront wiring (and often a DI container) — but the dependency graph stays explicit and changeable.

Singleton vs. a static utility class

A common interview probe: "why not just a class of static methods and fields instead of a Singleton?" A static utility class (Math-style) also gives one shared, globally-reachable bundle of state — but it can never implement an interface or be passed as an object, so you cannot substitute a fake in tests, cannot inject it, and cannot swap the implementation at runtime (test double, per-environment variant). A Singleton is still an instance: it can implement an interface, be handed to collaborators as that interface, and be mocked. So the rule is: if the shared thing is pure stateless functions with no need for polymorphism or mocking, a static utility class is simpler; the moment you need to program to an interface, inject it, or substitute it in a test, you need an object — either a Singleton or (better) a single injected instance.

When NOT to use a Singleton

Avoid the classic Singleton when the object carries mutable business state, when the code needs to be unit-tested in isolation, or when you may eventually need more than one instance (per tenant, per request, per environment). In those cases, create a single instance at the composition root and inject it instead — you keep "one shared object" without baking a global access point into every class. Reserve the textbook Singleton for genuinely process-wide, effectively-immutable concerns like a logger or a configuration snapshot.

Summary

The Singleton pattern guarantees one instance of a class and a global way to reach it. Its benefits — controlled access, optional lazy initialization, and tidy shared-resource management — come paired with real costs: global state, testing friction, tight coupling, and hidden dependencies. Use it deliberately for process-wide, stable concerns, and prefer injecting a single shared instance when you need testability or flexible lifetimes. If you do use a class-based Singleton, defend against the deserialization and reflection back doors — or use an enum, which the JVM protects for you.

Recall question

Why is the eager static final Singleton thread-safe without synchronized, and when would you still prefer a lazy variant such as the Bill Pugh holder or an enum?

Answer: The JVM initializes a class exactly once, and that initialization is thread-safe by specification. The eager final field is set during that one-time initialization, so every caller sees the fully-constructed instance without locks. You still prefer lazy variants when the singleton is expensive to create and might never be used, or when you want instance creation to fail gracefully on first use rather than at class-loading time. In Java, an enum is the safest published singleton because it also defeats reflection and serialization attacks.

Source

Based on the Gang of Four Design Patterns: Elements of Reusable Object-Oriented Software (Gamma, Helm, Johnson, Vlissides), Joshua Bloch, Effective Java, Item 3 ("Enforce the singleton property with a private constructor or an enum type"), and the Bill Pugh singleton-holder idiom. See also Refactoring.Guru, "Singleton Pattern." Re-authored and deepened for this guide — added the deserialization and reflection attack demonstrations with concrete Java code, the defenses (readResolve + constructor guard), the enum immunity explanation with JVM-spec references, and the variant comparison table.

🤖 Don't fully get this? Learn it with Claude

Stuck on Singleton Pattern? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.

🎨 Explain it visually

Build the mental picture, not memorization.

I just read a lesson on **Singleton Pattern** (OO & Low-Level Design) and want to truly understand it. Explain Singleton Pattern from first principles using ONE vivid real-world analogy and a visual mental model — draw it as ASCII art or a clear step-by-step diagram — with a concrete example using real numbers. Then ask me one question to check I got the mental picture, and wait for my reply. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🤔 Walk me through it (interactive)

Socratic — adapts to where you're stuck.

Teach me **Singleton Pattern** interactively. Ask me ONE guiding question at a time, wait for my answer, and adapt to my confusion — build the idea with me step by step instead of explaining it all at once. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧪 Quiz me & fix my gaps

Active recall exposes what you missed.

Quiz me on **Singleton Pattern** with 5 questions, easy to tricky, ONE at a time. Tell me if each answer is right; at the end, explain clearly what I got wrong and why. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧠 Make it stick

Intuition + hook + flashcards for long-term memory.

Help me remember **Singleton Pattern** for the long term: give the one-sentence intuition, a memorable hook/mnemonic, a tiny worked example, and 3 active-recall flashcards (Q -> A). If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.

📝 My notes