Creational 5 — Singleton
In one line
One instance per JVM, with a globally reachable accessor. Interviews love it because naive implementations break under concurrency.
Think of it like this
A country's president. There is only one at a time, and everyone who asks 'who is the president?' gets the same person.
Key ideas
- 01
The 4 safe forms: eager static final, enum, holder (Bill Pugh), and double-checked locking.
- 02
Why singletons are criticized: hidden global state, hard to test, hard to replace.
- 03
In Spring, singletons are the framework's job (one bean per context) — you usually don't write one.
- 04
Double-checked locking needs
volatileto publish the instance safely. - 05
The enum form also resists reflection and serialization attacks, which can create a second instance of the other forms.
Java / Spring map
- →
Spring @Singleton-scoped beans; java.lang.Runtime, System are de-facto singletons.
Code & diagrams
All four concurrency-safe forms.
// 0) Eager — simplest; built when the class is initialized
public final class ConfigEager {
private static final ConfigEager INSTANCE = new ConfigEager();
private ConfigEager() {}
public static ConfigEager get() { return INSTANCE; }
}
// 1) Enum — best, serialization- and reflection-safe, thread-safe by construction
public enum ConfigEnum { INSTANCE;
private final int maxRetries = 3;
public int maxRetries() { return maxRetries; }
}
// 2) Holder (Bill Pugh) — lazy, no synchronized on the hot path
public final class ConfigHolder {
private ConfigHolder() {}
private static final class Holder { static final ConfigHolder I = new ConfigHolder(); }
public static ConfigHolder get() { return Holder.I; }
}
// 3) Double-checked locking
public final class ConfigDCL {
private static volatile ConfigDCL INSTANCE; // volatile is the key
private ConfigDCL() {}
public static ConfigDCL get() {
if (INSTANCE == null) { // fast path, no lock
synchronized (ConfigDCL.class) {
if (INSTANCE == null) INSTANCE = new ConfigDCL();
}
}
return INSTANCE;
}
}Explain without notes
Why is double-checked locking safe only with volatile?
Practice
Write a thread-safe singleton you could use in a multi-threaded rate limiter (you'll need it in Phase 5).
Trade-offs
- ↔
Singleton hides global mutable state — Spring DI is the testable alternative.
Completion checklist
I can write all four safe forms and explain why naive lazy init breaks under concurrency.