What is Singleton?
Singleton can implement an interface (testability via mocks), static class — cannot. Singleton supports lazy initialization, static class initializes on class loading.
Junior Level
Singleton is a pattern that guarantees a class will have only one instance.
Why: When a resource is shared (log file, DB connection, configuration) and multiple copies would lead to conflicts or inconsistent state.
Simple analogy: A country can have only one president. If you ask “who is the president?”, you’ll always get the same person.
How it works:
- Private constructor (cannot create via
new) - Static field with the single instance
- Static method to get that instance
Example:
public class Logger {
// 1. The single instance
private static Logger instance = new Logger();
// 2. Private constructor
private Logger() {}
// 3. Method to get the instance
public static Logger getInstance() {
return instance;
}
public void log(String message) {
System.out.println(message);
}
}
// Usage — always the same object
Logger logger1 = Logger.getInstance();
Logger logger2 = Logger.getInstance();
System.out.println(logger1 == logger2); // true (same object!)
When to use:
- Logger (one for the entire application)
- Configuration (one settings file)
- DB connection (connection pool)
Singleton vs static class
Singleton can implement an interface (testability via mocks), static class — cannot. Singleton supports lazy initialization, static class initializes on class loading.
Middle Level
Singleton Implementations
1. Early Initialization (simple):
public class Singleton {
private static Singleton instance = new Singleton(); // On class loading
private Singleton() {}
public static Singleton getInstance() { return instance; }
}
// Thread-safe
// Not lazy (created even if not needed)
2. Lazy Initialization:
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
// Lazy
// Not thread-safe!
3. Thread-Safe (synchronized):
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
// Thread-safe
// Slow: synchronized adds ~10-50ns per call, critical in hot paths with millions of calls.
4. Enum Singleton (best):
public enum Singleton {
INSTANCE;
public void doWork() {
System.out.println("Working...");
}
}
// Usage
Singleton.INSTANCE.doWork();
// Thread-safe
// Protected from reflection
// Protected from serialization
How to “break” Singleton
1. Reflection:
// Ordinary Singleton can be broken
Constructor<Singleton> constructor = Singleton.class.getDeclaredConstructor();
constructor.setAccessible(true);
Singleton fake = constructor.newInstance(); // Second instance!
// Enum is protected
Constructor<SingletonEnum> constructor = SingletonEnum.class.getDeclaredConstructor();
// → IllegalArgumentException: Cannot reflectively create enum objects
2. Serialization:
// On deserialization a new object is created
ObjectOutputStream out = ...;
out.writeObject(Singleton.getInstance());
ObjectInputStream in = ...;
Singleton another = (Singleton) in.readObject(); // New object!
// Solution: readResolve() method
private Object readResolve() {
return getInstance(); // Return existing instance
}
3. ClassLoader:
// Multiple ClassLoaders → multiple Singletons!
// One in Tomcat, another in OSGi
Singleton in Spring
// Spring manages Singleton itself
@Component // Singleton scope by default!
public class UserService { }
// Always the same bean
@Autowired UserService service1;
@Autowired UserService service2;
// service1 == service2 → true
Typical Mistakes
- Singleton instead of DI
// Hidden dependency public class OrderService { public void create() { Logger.getInstance().log("..."); // Hidden dependency! } } // DI approach public class OrderService { private final Logger logger; public OrderService(Logger logger) { this.logger = logger; } } - Mutable state in Singleton
// Mutable Singleton = concurrency problems public class Counter { private int count = 0; // Race condition! public void increment() { count++; } }
Senior Level
Contextuality of Singleton
“Single instance” is relative:
| Context | Uniqueness |
|---|---|
| JVM | One instance per JVM |
| ClassLoader | One per ClassLoader (can be multiple!) |
| Spring Context | One per ApplicationContext |
| Distributed system | DOES NOT EXIST (needs distributed lock) |
In a cluster:
Node 1: Singleton instance A
Node 2: Singleton instance B
Node 3: Singleton instance C
→ 3 instances! Need Redis/Zookeeper for coordination
Java Memory Model and Singleton
JMM (Java Memory Model) — specification defining how threads see each other’s memory. Bill Pugh Singleton — named after the researcher who proposed the static inner class solution. SRP (Single Responsibility Principle).
Visibility problem without volatile:
// Unsafe code
public class UnsafeSingleton {
private static UnsafeSingleton instance;
public static UnsafeSingleton getInstance() {
if (instance == null) {
instance = new UnsafeSingleton();
}
return instance;
}
}
// Thread 1: allocated memory → published reference → called constructor
// Thread 2: sees instance != null → gets UNINITIALIZED object!
// Solution: volatile + double-checked locking
private static volatile UnsafeSingleton instance;
public static UnsafeSingleton getInstance() {
UnsafeSingleton local = instance;
if (local == null) {
synchronized (UnsafeSingleton.class) {
local = instance;
if (local == null) {
instance = local = new UnsafeSingleton();
}
}
}
return local;
}
Why volatile is critical:
- Without volatile: instruction reorder (allocate memory → publish → constructor)
- With volatile: happens-before guarantee → constructor COMPLETED before publishing
Singleton as Anti-pattern
Problems:
- Tight Coupling
// Dependency not visible in signature public class OrderService { public void process() { Database.getInstance().save(...); // Hidden dependency! } } - Testability
// Impossible to mock @Test void testOrder() { // Singleton preserves state between tests! // Impossible to substitute Database.getInstance() } - SRP Violation
// The class is responsible for: // 1. Business logic // 2. Managing its own lifecycle // 3. Concurrent access - Memory Leak
// Singleton lives forever (static field) // In Tomcat on redeploy → old ClassLoader not GC // → Metaspace Leak
Bill Pugh Singleton (Static Holder)
public class BillPughSingleton {
private BillPughSingleton() {
if (INSTANCE_HOLDER.INSTANCE != null) {
throw new IllegalStateException("Already initialized");
}
}
private static class INSTANCE_HOLDER {
static final BillPughSingleton INSTANCE = new BillPughSingleton();
}
public static BillPughSingleton getInstance() {
return INSTANCE_HOLDER.INSTANCE;
}
}
// JVM guarantees:
// 1. Laziness (class loads only on first call)
// 2. Thread-safety (class initialization is thread-safe)
// 3. No synchronized overhead
GC and Singleton
// Singleton will NOT be GC'd while:
// 1. ClassLoader is alive
// 2. Reference to static field exists
// In standard Java: ClassLoader lives until process ends
// → Singleton lives "forever"
// In Tomcat/OSGi: ClassLoader can be unloaded
// → But Singleton prevents GC → Memory Leak
Production Experience
Real scenario #1: Singleton killed testability
- 500 tests, all use
Config.getInstance() - Problem: tests depend on each other (shared state)
- Solution: migrated to Spring DI
- Result: isolated tests, parallel execution
Real scenario #2: Singleton in a cluster
- ID generator as Singleton
- Problem: 5 nodes in cluster → 5 generators → duplicate IDs!
- Solution: Redis INCR for ID generation
- Lesson: Singleton != distributed uniqueness
Best Practices
- DON’T write Singleton manually in Spring applications
- Use DI (
@Component= Singleton scope) - Enum — safest for libraries/SDKs
- Bill Pugh — for lazy initialization
- Avoid mutable state in Singleton
- readResolve() for serialization protection
- Constructor check for reflection protection
- In clusters → Redis/Zookeeper for coordination
Senior Summary
- Singleton != distributed uniqueness — only within a JVM
- Enum — the only protection from reflection/serialization attacks
- DI container replaces manual Singleton in 99% of cases
- Memory Model: volatile is critical for DCL
- Testability: Singleton = enemy #1 of unit tests
- GC: Singleton lives forever — be careful with resources
- Bill Pugh = laziness + thread-safety without synchronized
- Hidden dependencies = tight coupling = technical debt
Interview Cheat Sheet
Must know:
- Singleton guarantees a single class instance through private constructor + static access method
- Enum Singleton — safest: protection from reflection and serialization out of the box
- Bill Pugh (Static Holder) — lazy initialization without synchronized, via static inner class
- In Spring @Component = Singleton scope by default, DON’T write Singleton manually
- Singleton doesn’t work in a cluster — each node creates its own instance
- Without volatile in DCL, reordering is possible: thread gets uninitialized object
- Singleton is considered an anti-pattern: violates SRP, DIP, testability
Common follow-up questions:
- How to “break” Singleton? — Reflection (create new instance), serialization (deserialization creates new object), ClassLoader (multiple loaders)
- Why is Enum better than ordinary Singleton? — JVM forbids reflectively creating enums, serialization works correctly
- When is Singleton acceptable? — Loggers, configuration, caches — stateless or immutable objects
- What is Bill Pugh Singleton? — Lazy initialization via static inner class, JVM guarantees thread-safety
Red flags (DO NOT say):
- “I use Singleton for storing state in Spring” — Spring manages this through DI
- “Singleton works in a cluster” — each node creates its own instance
- “My Singleton is thread-safe without volatile” — DCL without volatile = undefined behavior
- “Singleton is the best pattern” — it’s one of the most criticized patterns
Related topics:
- [[04. How to implement thread-safe Singleton]] — implementation approaches
- [[05. What is double-checked locking]] — Singleton optimization
- [[06. What are problems with Singleton]] — anti-patterns and issues
- [[02. What pattern categories exist]] — Singleton as a Creational pattern
- [[16. What anti-patterns do you know]] — Singleton as a source of problems