Classical Synchronization ProblemsThread-Safe Singleton & Double-Checked LockingHard⏱️ ~3 min

Common Mistakes and Interview Traps

Key Insight
Thread-safe singleton is a favorite interview topic because it tests understanding of memory models, not just locking. Most candidates make subtle errors.

Mistake 1: Missing Volatile

The most common error. Writing DCL in Java without volatile on the instance field. It compiles, it usually works, but it is broken. Under high concurrency or with certain JVMs, threads see partially constructed objects.

Mistake 2: Synchronizing on the Instance

Some candidates try synchronized(instance). This cannot work - the instance is null when you need the lock most! You must synchronize on a separate lock object or the class itself.

Mistake 3: Thinking Single Check Is Enough Inside Lock

If you remove the outer check, you pay lock cost on every call. If you remove the inner check, two threads that passed the outer check simultaneously will both create instances. Both checks are necessary.

Why Both Checks Are Required
Thread AThread BOuter check: nullOuter check: nullAcquires lock, createsWaits for lock...Inner check: not null!
Inner check saves Thread B from creating duplicate

Mistake 4: Forgetting About Serialization

Deserialization creates a new object, bypassing your getInstance(). In Java, implement readResolve() to return the existing instance. Or use enum singleton which handles this automatically.

Mistake 5: Reflection Attacks

Reflection can call private constructors. Malicious or buggy code can create additional instances. Defense: throw an exception if the constructor is called when instance exists. Or use enum - reflection cannot instantiate enums.

Interview Tip: When asked to implement thread-safe singleton, state the volatile requirement immediately. Then mention you would prefer the holder pattern or enum. This shows you understand both the problem and the better solutions.
💡 Key Takeaways
Missing volatile is the classic DCL bug. The code looks correct but allows threads to see partially constructed objects.
Cannot synchronize on the instance itself - it is null when you need protection. Use a class-level lock or separate lock object.
Both checks are required. Outer check is for performance (skip lock). Inner check is for correctness (prevent duplicate creation).
Serialization breaks singleton by creating new instances on deserialization. Implement readResolve() or use enum.
Reflection can bypass private constructors. Enum singleton is immune. For classes, throw exception if instance already exists.
📌 Examples
1Broken Java DCL: if (instance == null) { synchronized(Singleton.class) { if (instance == null) instance = new Singleton(); }} Missing volatile!
2Wrong lock target: synchronized(instance) - throws NullPointerException when instance is null, which is exactly when you need the lock.
3Serialization attack: ObjectOutputStream writes singleton, ObjectInputStream reads it. Now two instances exist in same JVM.
← Back to Thread-Safe Singleton & Double-Checked Locking Overview