What is a Thread-Safe Singleton?
What makes a Singleton thread-safe in Java — eager init, double-checked locking, holder idiom and enum singletons compared.
Expected Interview Answer
A thread-safe Singleton is an implementation of the Singleton pattern that guarantees exactly one instance is created and visible to every thread even when multiple threads request the instance for the first time simultaneously, without relying on external coordination from the caller.
The simplest thread-safe form is eager initialization: create the instance at class-loading time as a static final field, which the JVM guarantees happens exactly once before any thread can observe it, at the cost of creating the object even if it is never used. For lazy creation, safe options include a synchronized getInstance() method (simple but adds locking overhead to every call), double-checked locking with a volatile field (locks only during the rare first-creation window), the static holder idiom (piggybacks on JVM class-loading guarantees for lazy, lock-free safety), or an enum singleton (the language runtime guarantees single instantiation, and it is also immune to reflection-based and serialization-based instance duplication). Choosing between them is a tradeoff between “eager and simple” versus “lazy and either mildly more complex or effectively free once loaded.”
- Guarantees a single, consistent instance under concurrent first access
- Eliminates a class of race-condition bugs invisible in single-threaded testing
- Several idioms achieve this with little or no explicit locking overhead
- Enum form additionally defends against reflection and serialization attacks
AI Mentor Explanation
A thread-safe singleton is like a ground with only one official scoreboard operator role — no matter how many officials show up at the gate wanting to claim the role at the exact same moment, the appointment process guarantees only one person is ever actually handed the job. An unsafe version is a gate with no such guarantee, where two officials could both walk in believing they got the role. Thread safety is the guarantee baked into the process itself, not something each official has to figure out on their own.
Step-by-Step Explanation
Step 1
Choose eager or lazy
Eager: static final field created at class load, always thread-safe. Lazy: needs explicit coordination.
Step 2
For lazy creation, pick a safe idiom
Synchronized method, double-checked locking with volatile, holder idiom, or enum.
Step 3
Guard the first-creation window
This is the only moment concurrent threads can conflict — after creation, reads are safe.
Step 4
Verify against reflection/serialization
If robustness against these attacks matters, prefer the enum form.
What Interviewer Expects
- Distinguishing eager (always safe) from lazy (needs a safe idiom) initialization
- Naming at least two concrete thread-safe lazy approaches
- Understanding that the danger window is only the first concurrent creation
- Mentioning enum as the most attack-resistant option
Common Mistakes
- Assuming any Singleton implementation is automatically thread-safe
- Using a plain if (instance == null) check with no synchronization
- Not knowing eager initialization is inherently thread-safe with zero locking
- Confusing thread safety with immutability of the singleton’s own fields
Best Answer (HR Friendly)
“A thread-safe Singleton guarantees that even if many threads ask for the instance at the exact same time before it exists, only one instance ever gets created, and everyone ends up using the same object. The simplest way is to create the instance eagerly when the class loads, which is automatically safe; for lazy creation you use techniques like double-checked locking or a holder class that rely on language guarantees instead of hoping callers coordinate themselves.”
Code Example
class EagerSingleton {
// created at class-load time, JVM guarantees this happens once
private static final EagerSingleton INSTANCE = new EagerSingleton();
private EagerSingleton() {}
static EagerSingleton getInstance() { return INSTANCE; }
}
enum EnumSingleton {
INSTANCE;
void doWork() { System.out.println("working"); }
}
EagerSingleton a = EagerSingleton.getInstance();
EnumSingleton.INSTANCE.doWork(); // guaranteed single instance, reflection-safeFollow-up Questions
- Why is eager initialization inherently thread-safe with no locking code?
- What is the tradeoff of eager initialization versus lazy initialization?
- How does the enum form resist reflection-based instance duplication?
- When would a synchronized getInstance() method be an acceptable simple choice?
MCQ Practice
1. Which Singleton initialization style is inherently thread-safe with no extra locking?
The JVM guarantees a static final field is initialized exactly once before any thread can observe it.
2. What is the main downside of eager Singleton initialization?
Eager initialization trades unnecessary upfront object creation for automatic thread safety.
3. Which thread-safe Singleton form also resists reflection-based duplication?
The JVM enforces that enum constants cannot be instantiated more than once, even via reflection.
Flash Cards
Thread-safe Singleton in one line? — Guarantees exactly one instance even under concurrent first access, without caller coordination.
Simplest thread-safe form? — Eager initialization via a static final field created at class load.
Best lazy, lock-free option? — The static holder idiom, relying on JVM class-loading guarantees.
Most attack-resistant form? — Enum singleton — immune to reflection and serialization duplication.