All topics
library
intermediate

Singleton Pattern & Thread Safety

Implement thread-safe singletons correctly, and know why the double-checked locking idiom requires volatile.

One instance for the whole application. The difficulty is doing it safely without paying for a lock on every call.

Singleton = a country's president. There's exactly one at any time. The enum approach = it's written in the constitution (bulletproof). Double-checked locking = asking two guards independently and hoping they agree (fragile without proper protocol/volatile).

Key Concepts

1
Use an enum. It is the simplest correct answer.
    public enum Registry {
      INSTANCE;
      private final Map<String, String> data = new ConcurrentHashMap<>();
      public void put(String k, String v) { data.put(k, v); }
    }
2
The JVM initialises it once, under its own lock, and serialization and reflection cannot produce a second instance. Nothing else gives you all three.
3
The static holder is the next best, and the one to use when you need a real class:
4
    public class Registry {
      private Registry() { }
      private static class Holder {
        static final Registry INSTANCE = new Registry();
      }
      public static Registry getInstance() { return Holder.INSTANCE; }
    }
5
Holder is not loaded until getInstance() first runs, so it is lazy. Class initialisation is already thread-safe, so there is no synchronisation to write and none to pay for.
HoldergetInstance()
6
Double-checked locking is the interview question.
    private static volatile Registry instance;
7
    public static Registry getInstance() {
      if (instance == null) {                 // no lock in the common case
        synchronized (Registry.class) {
          if (instance == null)               // check again, holding the lock
            instance = new Registry();
        }
      }
      return instance;
    }
8
volatile is not optional here. new Registry() is three steps — allocate, run the constructor, assign the reference — and the JVM may reorder the last two. Without volatile, another thread can see a non-null reference to an object whose constructor has not finished, and read fields that are still zero.
volatilenew Registry()
9
That reordering is legal, and it broke this idiom entirely before the Java 5 memory model gave volatile its ordering guarantee.
volatile
10
The weaker options.
    synchronized getInstance()   correct, locks on every call
    static final INSTANCE = ...  correct, never lazy
11
In practice you rarely write one. A Spring @Component is a singleton managed by the container, which also makes it injectable and replaceable in a test — the thing a hand-rolled singleton makes hard.
@Component
12
What the interviewer is probing.1. "Why does double-checked locking need volatile?" Probing: reordering, which is the real answer. Stalls: "For visibility." Moves up: object construction is allocate, construct, assign, and the last two can be reordered — so another thread can see a non-null reference to a half-built object.
13
2. "What is the simplest correct singleton?" Probing: whether you reach for the enum. Stalls: "A static field with a null check." Moves up: an enum with one constant — thread-safe by class initialisation, and safe against serialisation and reflection, which nothing else gives you.
14
3. "How does the holder idiom achieve laziness without locking?" Probing: class initialisation semantics. Stalls: "It uses a lock internally." Moves up: the inner class is not loaded until first referenced, and class initialisation is already thread-safe, so the JVM does the work.
15
4. "Why do you rarely write one in a Spring application?" Probing: context. Stalls: "You still do." Moves up: a container-managed bean is already a singleton, and it stays injectable and replaceable in tests, which a hand-rolled one makes hard.