Low-Level Design (LLD)
PatternsCreational Patterns·4 min revision·Updated 2026-10-29

Singleton Pattern

Singleton → ensure class has exactly one instance + provide global access point.

#LLD#Patterns#Java#Singleton Pattern
1-Minute Revision Card
Singleton Pattern
Core Entities & Components
SingletonFactorySingletonInterfaceConcreteProduct
Architecture & Patterns
Singleton Pattern
Key Methods, APIs & Formulas
create()getInstance()process()
Exact Phrases to Say in the Interview
  • “I will apply Singleton Pattern here to encapsulate changes and satisfy Open/Closed principle.”
  • “De-couples core execution from specific implementations.”

Singleton Pattern

Singleton Pattern

1. ONE-LINE IDEA

Singleton → ensure class has exactly one instance + provide global access point.

Examples: application config, shared logger, in-memory registry.

2. REQUIREMENTS

  • One instance per JVM/classloader.
  • Global access via getInstance().
  • Lazy or eager initialization.
  • Thread-safe creation.
  • Prevent duplicate instances through normal construction.
  • Serialization/reflection considerations when strict uniqueness matters.

3. CORE ENTITIES

  • Singleton → private constructor, static instance, public accessor.
  • Client → gets shared instance.

4. UML DIAGRAM

plain
+----------------------------+
|         Singleton          |
+----------------------------+
| - instance: Singleton      |  {static}
+----------------------------+
| - Singleton()              |
| + getInstance(): Singleton |  {static}
+----------------------------+

5. IMPLEMENTATION OPTIONS

Option A: Eager initialization

Java

java
public final class AppConfig {
    private static final AppConfig INSTANCE = new AppConfig();

    private AppConfig() {}

    public static AppConfig getInstance() {
        return INSTANCE;
    }
}
  • Thread-safe class initialization.
  • Simple.
  • Instance created even if never used.

Option B: Lazy initialization — unsafe

Java

java
public final class AppConfig {
    private static AppConfig instance;

    private AppConfig() {}

    public static AppConfig getInstance() {
        if (instance == null) {
            instance = new AppConfig();
        }
        return instance;
    }
}

Problem: Two threads can both see null → create two instances.

Never use this version in concurrent code.

Option C: Synchronized accessor

Java

java
public final class AppConfig {
    private static AppConfig instance;

    private AppConfig() {}

    public static synchronized AppConfig getInstance() {
        if (instance == null) {
            instance = new AppConfig();
        }
        return instance;
    }
}

Thread-safe, but synchronization occurs on every call.

Option D: Double-checked locking

Java

java
public final class AppConfig {
    private static volatile AppConfig instance;

    private AppConfig() {}

    public static AppConfig getInstance() {
        if (instance == null) {
            synchronized (AppConfig.class) {
                if (instance == null) {
                    instance = new AppConfig();
                }
            }
        }
        return instance;
    }
}
  • Lazy creation.
  • Thread-safe with volatile.
  • Avoids locking after initialization.
  • More complex than necessary for most cases.

volatile prevents unsafe publication/reordering and ensures visibility.

Option E: Bill Pugh — initialization-on-demand holder

Java

java
public final class AppConfig {
    private AppConfig() {}

    private static class Holder {
        private static final AppConfig INSTANCE = new AppConfig();
    }

    public static AppConfig getInstance() {
        return Holder.INSTANCE;
    }
}

Good default for lazy Singleton in Java.

  • Lazy initialization.
  • Thread-safe through JVM class initialization.
  • No explicit synchronization.

Option F: Enum Singleton — strongest simple option

Java

java
public enum AppConfig {
    INSTANCE;

    public void printConfig() {
        System.out.println("Config loaded");
    }
}

Usage:

Java

java
AppConfig.INSTANCE.printConfig();
  • Thread-safe.
  • Serialization-safe by Java enum rules.
  • Strong protection against reflective construction.
  • Not lazy in the same way as holder idiom; enum initialization occurs when enum class initializes.

6. COMPLETE RUNNABLE EXAMPLE

Use holder idiom:

Java

java
public final class Singleton {
    private Singleton() {}

    private static class Holder {
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        return Holder.INSTANCE;
    }

    public void execute() {
        System.out.println("Singleton executing");
    }
}

public class Main {
    public static void main(String[] args) {
        Singleton first = Singleton.getInstance();
        Singleton second = Singleton.getInstance();

        first.execute();
        System.out.println(first == second);
    }
}

Output:

plain
Singleton executing
true

== checks object identity, confirming both references point to same instance.

7. THREAD SAFETY

ApproachThread-safe?Lazy?
Eager static fieldYesNo
Naive lazyNoYes
Synchronized accessorYesYes
Double-checked locking + volatileYesYes
Holder idiomYesYes
EnumYesOn enum initialization

8. INTERVIEW QUESTIONS

Q: Why private constructor?

Prevents normal external instantiation using new.

Q: Why static instance?

Instance belongs to class, not individual objects.

Q: Why volatile in double-checked locking?

Without it, unsafe publication/reordering can expose incompletely initialized object.

Q: Can reflection break Singleton?

Private constructors can often be accessed reflectively. Enum Singleton has stronger protection against reflective instantiation.

Q: Can serialization create another instance?

Ordinary serializable Singleton may deserialize into another object unless readResolve() returns canonical instance. Enum serialization handles identity automatically.

Q: Is Singleton always good?

No. Global mutable state creates hidden dependencies, testing difficulty, and concurrency risks.

Q: Singleton vs static class?

Singleton is an object → can implement interfaces, be passed as dependency, and participate in polymorphism. Static methods aren't instance-polymorphic.

Q: Singleton vs Dependency Injection?

Singleton controls instance creation/access. DI controls dependency construction and wiring. DI container can manage singleton-scoped objects without implementing Singleton Pattern manually.

9. REAL-WORLD USE

  • Shared immutable config.
  • Logger registry.
  • Process-wide metrics registry.
  • Cache manager, when one shared instance is intentional.

Avoid assuming Singleton automatically means one instance across multiple JVMs, containers, or classloaders. It normally means one instance per defining classloader.

10. QUICK REVISION

  • Private constructor.
  • Static instance.
  • Public static accessor.
  • Thread safety matters.
  • Holder idiom → strong lazy default.
  • Enum → simplest robust Singleton.
  • Global mutable state → testing + coupling risks.

11. MEMORY TRICK

One class → one instance → one access point.

Abhinandan Mishra

SDE-II · Distributed Systems · Developer Tools

© 2026 Abhinandan Mishra

Built with Next.js & Tailwind CSS

abhinandanmishra360@gmail.com