Common Mistakes and Interview Traps
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.
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.