How do you ensure a class has exactly one instance when multiple threads might try to create it simultaneously?
Why Singleton Matters
Some resources should exist only once in your application. A database connection pool. A configuration manager. A logging service. Creating multiple instances wastes memory, causes inconsistency, or breaks the application entirely.
The Single-Threaded Solution Is Easy
Check if the instance exists. If not, create it. Return the instance. Simple. But this breaks spectacularly with multiple threads.
The Multi-Threaded Disaster
Thread A checks: instance is null. Thread B checks: instance is null. Both think they should create it. Both create it. Now you have two singletons. The whole point is defeated.
Race Condition in Naive Singleton
Result: Two instances created!
Real-World Consequences
Connection pools: Two pools means twice the connections, potentially exhausting database limits. Caches: Data gets cached in one instance, reads miss in the other. Counters: Statistics become meaningless as updates split between instances.
The Challenge: Make singleton creation atomic without killing performance. You cannot lock every access - that is too slow. You cannot skip locking - that breaks correctness.
💡 Key Takeaways
✓Singleton pattern ensures exactly one instance exists. Thread-safety makes this work when multiple threads call getInstance() simultaneously.
✓The naive check-then-create pattern fails because the check and creation are not atomic. Two threads can both pass the null check.
✓Creating multiple singletons wastes resources and causes inconsistent state. A config manager with two instances returns different values.
✓The challenge is achieving thread-safety without sacrificing performance. Locking every call to getInstance() is correct but slow.
✓This problem appears in every language and framework. Database pools, loggers, caches, and service locators all face this challenge.
📌 Examples
1Database connection pool: Two pools created, each opens 10 connections. Database limit is 15. Application crashes when both pools try to use their connections.
2Configuration manager: Thread A gets instance 1, Thread B gets instance 2. A updates a setting, B never sees it. Debugging nightmare.
3Metrics counter: getInstance() called 1000 times during startup. Race condition creates 3 instances. Metrics split across them, totals are wrong.