How do you make a Singleton thread-safe in Java?
Use eager initialisation, the holder class idiom, or an enum. If you need lazy creation with double-checked locking, the field must be volatile.
Explain it simply
With lazy creation, two threads can both see "no instance yet" at the same moment and each create one, so you end up with two Singletons. It is like two clerks both opening the last file cabinet because neither saw the other doing it.
The safest options let the JVM's class loading guarantee do the locking for you.
Example
// 1. Holder idiom: lazy and safe, no explicit locking
class Settings {
private Settings() { }
private static class Holder { static final Settings I = new Settings(); }
static Settings get() { return Holder.I; }
}
// 2. Enum: simplest, also safe against reflection and serialization tricks
enum Registry { INSTANCE; }
// 3. Double-checked locking: needs volatile
class Cache {
private static volatile Cache instance;
private Cache() { }
static Cache get() {
if (instance == null) { // first check, no lock
synchronized (Cache.class) {
if (instance == null) { // second check, with lock
instance = new Cache();
}
}
}
return instance;
}
}Without volatile, another thread may see a half-constructed object because of instruction reordering.
What to say in the interview
"I prefer the holder idiom or an enum, since class initialisation is thread-safe by the JVM. If I use double-checked locking, the instance field must be volatile, otherwise a thread may see a partially constructed object."
Common mistakes
- Leaving out volatile in double-checked locking.
- Synchronising the whole getter, which is correct but slows every call.