0/0
Design Patterns

Singleton Pattern

One instance, global access β€” and four ways to build it. Trade-offs from eager construction to the Bill Pugh holder idiom.

Explore Topics

🎯
Intent
Ensure exactly one instance β€” and offer a global way to reach it.
πŸ§ͺ Singleton Variant Lab β€” 4 variants Γ— 4 scenarios
πŸš€ App Startup: JVM boots, classes get loaded. No client has touched the singleton yet.
Eager Initialization
instances: 1
When created: Built at class load
thread-safe: βœ“ yesexception-safe: βœ— no
Already constructed before main() runs.
Static Block Init
instances: 1
When created: Built in static block at class load
thread-safe: βœ“ yesexception-safe: βœ“ yes
Constructor runs inside try/catch β€” checked exceptions become RuntimeException.
Lazy Initialization
instances: 0
When created: Not yet built
thread-safe: β€”exception-safe: β€”
Singleton class loaded but the `instance` field is still null.
Bill Pugh Holder
instances: 0
When created: Holder class NOT loaded yet
thread-safe: βœ“ yesexception-safe: β€”
Outer class is loaded, but the nested Holder is deferred β€” true laziness.
PropertyEagerStatic BlockLazyBill Pugh
Lazy?βœ—βœ—βœ“βœ“
Thread-safe?βœ“ (JVM)βœ“ (JVM)βœ—βœ“ (JVM)
Exception handling?βœ—βœ“ try/catchcaller seesβœ“ in Holder
Performancefastestfastestfastest (no sync)fastest
Verdictalways-needalways + throwsteaching onlymodern default β˜…
Pick a scenario above to see how each variant behaves. Toggle Matrix ↔ Timeline for the two perspectives.
🎯
Intent
Ensure exactly one instance β€” and offer a global way to reach it.

Singleton is a creational design pattern that guarantees a class has only one instance and provides a single global access point to that instance. It also encapsulates "just-in-time initialization" β€” the instance comes into existence on first use, not by anyone calling `new` from outside. The pattern actually solves two problems at once (uniqueness + access), which is exactly why it is sometimes criticized as an SRP violation: a class is taking on both its business responsibility and the responsibility of policing its own creation.

Key Ideas
  • Hide the constructor (private) so nobody outside the class can call `new`.
  • Hold the unique instance in a private static field.
  • Expose a public static `getInstance()` that returns that one instance.
  • Solves uniqueness AND access in one pattern β€” which is also the SRP complaint.
  • Variants differ only in WHEN and HOW the instance is created.
Strengths
  • ✦Guaranteed single instance across the whole JVM
  • ✦Globally reachable without parameter-passing
  • ✦Lazy variants delay heavy initialization
  • ✦Centralizes control of a shared resource
Weaknesses
  • β–³Smuggles global state into the design
  • β–³Hides dependencies β€” callers don't see what they rely on
  • β–³Hard to unit-test (cannot mock the call to a static method)
  • β–³Mixes uniqueness concern with business logic (SRP debate)
Used in:Configuration manager, logger, thread pool, connection pool, and ID/account-number generators all need exactly one shared instance per process.
Code Snippets

Quiz

Intent Quiz
QUIZ 1/6
Which statement best captures the GoF Intent of the Singleton pattern?

Diagrams

UML Class Diagram β€” the GoF Singleton structure
Loading diagram...
Which Singleton variant should I use? β€” decision flow
Loading diagram...

Practice

Drag each property to the Singleton variant it BEST describes. Each variant accepts exactly two properties.
EXERCISE 1/4
Built at class load β€” wastes init cost if unused
Simplest reference, no synchronization needed
Wraps construction in try/catch for checked exceptions
Eager + exception handling, still not lazy
NOT thread-safe under concurrent first-time access
Textbook idiom for teaching lazy initialization
Uses a nested static Holder class
Lazy AND thread-safe by JVM guarantee β€” no synchronized
Eager Initialization
Static Block Initialization
Lazy Initialization
Bill Pugh (Holder Idiom)
Spot the bug β€” why is this NOT a real Singleton?
EXERCISE 2/4
Click on the line you think contains the bug, then press Confirm.
1public class BankConfig {
2 public static BankConfig instance = new BankConfig();
3
4 public BankConfig() {
5 System.out.println("BankConfig built");
6 }
7
8 public static BankConfig getInstance() {
9 return instance;
10 }
11}
12
13// Caller code:
14BankConfig a = BankConfig.getInstance();
15BankConfig b = new BankConfig();
16System.out.println(a == b); // prints "false"
Complete the Bill Pugh holder-idiom singleton
EXERCISE 3/4
public class Config { // Block external construction: Config() { /* load config */ } // The lazy, thread-safe holder: private class Holder { private static final Config INSTANCE = new Config(); } public static Config getInstance() { return .INSTANCE; } }
Singleton myths and gotchas β€” true or false?
EXERCISE 4/4
A class with all static fields and static methods is the same as a Singleton.
The textbook lazy initialization (if instance == null then new ...) is thread-safe out of the box.
Bill Pugh's holder idiom requires no `synchronized` keyword to be thread-safe.
The Singleton pattern is just a fancy name for a global variable.
In Java, marking a Singleton as `Serializable` is enough to preserve its singleton-ness across serialization.
Eager Singleton wastes nothing β€” the instance is only "built" once anyway.
A Bill Pugh Singleton's Holder class is loaded when the outer class is loaded.

References

πŸ“š

Design Patterns: Elements of Reusable Object-Oriented Software β€” Singleton chapter

en.wikipedia.org

book
πŸ“„

Refactoring.Guru β€” Singleton Pattern (problem, structure, code)

refactoring.guru

article
πŸ“„

Initialization-on-demand holder idiom (Bill Pugh) β€” Wikipedia

en.wikipedia.org

article
πŸ“„

Baeldung β€” Singletons in Java (all four variants compared)

baeldung.com

article
πŸ“š

Effective Java β€” Item 3: Enforce the singleton property with a private constructor or an enum type

oreilly.com

book