Hook: A singleton is like the one master key for a building: useful when everyone truly needs the same lock, dangerous if you hand it out carelessly.
Question: What is the Singleton Pattern?
Answer: The Singleton Pattern ensures that a class has only one instance and gives a controlled way to reach it. In Java, that usually means making the constructor private and exposing a static access point such as getInstance() or an enum constant. It is popular because it combines object creation, thread safety, and design trade-offs in one simple idea.
Interview-Ready Answer: I would say a singleton is a class that allows exactly one shared instance and gives everyone a single place to access it. In Java, I usually prefer an enum singleton or a static holder because they are thread-safe and simple. The big things I watch for are lazy creation, serialization, reflection, and class-loader edge cases, because those are the places a singleton usually breaks.
Detailed Explanation: A singleton means one class, one live object, and one shared access point. It is used when many parts of a program must coordinate through the same state, such as a cache, a configuration reader, or a registry. The key idea is not just global access; it is controlled creation.
new.enum constant.getInstance().That last step is where the Java Memory Model matters. The memory model is the set of rules that decides when one thread can see another thread's writes. Without safe publication, one thread can observe a reference to an object before the constructor has fully finished.
| Approach | State | Testability | Typical use |
|---|---|---|---|
| Singleton | Shared | Medium | Cache, registry |
| Static utility | None | High | Pure helpers |
| DI bean | Shared or scoped | High | Services in frameworks |
Common singleton forms are eager initialization, lazy holder, synchronized getter, double-checked locking, and enum. A lazy holder means a nested class holds the instance, and the JVM loads that nested class only when it is first referenced. Double-checked locking means checking for null before and after entering a lock. The volatile keyword means every thread sees the latest value, which prevents harmful reordering and half-built objects.
getInstance() is O(1); it does constant-time work after the object exists.volatile. Before that, it was a classic bug source.enum singletons are the most robust because the JVM protects them.Memory Hook: Think of a singleton as the building's one reception desk: everyone can reach it, but only one desk is ever built.
Real-World Story: In a checkout service, a singleton TaxRateCache held the latest regional tax rules so every request priced carts the same way. A developer changed it to a lazy class without synchronization, and under peak load two threads created two separate instances. One instance refreshed from Redis, the other stayed stale, so the same cart could be priced two different ways for a few seconds.
The symptoms were easy to miss at first: logs showed duplicate Loading tax rates lines, Redis connection counts jumped, and support started seeing tickets about random totals changing between page refreshes. The business impact was real: some customers abandoned checkout because the final amount looked unstable. The fix was to restore a safe singleton design and move refresh logic into an explicit method so updates were controlled instead of accidental.
import java.lang.reflect.Constructor;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class SingletonDemo {
public static void main(String[] args) throws InterruptedException {
SafeCounter first = SafeCounter.INSTANCE;
first.increment();
first.increment();
System.out.println("Initial count: " + first.getCount());
// All threads hit the same object, so the final count should be exact.
int threads = 8;
int perThread = 1000;
ExecutorService pool = Executors.newFixedThreadPool(threads);
CountDownLatch done = new CountDownLatch(threads);
for (int i = 0; i < threads; i++) {
pool.submit(() -> {
try {
for (int j = 0; j < perThread; j++) {
first.increment();
}
} finally {
done.countDown();
}
});
}
if (!done.await(5, TimeUnit.SECONDS)) {
System.out.println("Timed out waiting for workers.");
}
pool.shutdown();
System.out.println("Count after concurrent increments: " + first.getCount());
SafeCounter second = SafeCounter.INSTANCE;
System.out.println("Same instance? " + (first == second));
System.out.println("Identity hash codes: " + System.identityHashCode(first) + " / " + System.identityHashCode(second));
tryReflectionAttack();
}
private static void tryReflectionAttack() {
try {
// Enum singletons are protected by the JVM itself; reflective construction is blocked.
Constructor<?> ctor = SafeCounter.class.getDeclaredConstructors()[0];
ctor.setAccessible(true);
Object fake = ctor.newInstance("FAKE", 1);
System.out.println("Unexpectedly created: " + fake);
} catch (Exception e) {
System.out.println("Reflection attack failed as expected: " + e.getClass().getSimpleName() + " - " + e.getMessage());
}
}
enum SafeCounter {
INSTANCE;
private int count = 0;
public synchronized void increment() {
count++;
}
public synchronized int getCount() {
return count;
}
}
}Follow-up & Tricky Questions:
enum, or double-checked locking with a volatile field. The goal is safe publication so only one object is created and every thread sees the fully built instance.enum often the best singleton in Java? It is simple, thread-safe by construction, and protects you from reflection and serialization issues. For most interview answers, saying enum is the safest default is a strong point.null before locking and again inside the lock. This reduces synchronization cost after initialization, but it only works correctly with volatile.enum singletons are initialized when the enum class is initialized, which is usually not treated as truly lazy.enum singleton lazy? Not exactly. The instance is created when the enum class is initialized, so it is safe and simple, but not lazy in the same way a holder class is.volatile make code mutually exclusive? No. volatile gives visibility, not mutual exclusion. You still need locking or another safe pattern when creating the object.Common Mistakes:
new, but it does not make the class thread-safe or protect it from reflection. Fix: use a safe creation strategy such as a holder or enum.null and create two objects. Fix: use a lock, a holder class, or enum.enum or add defenses like readResolve().Memory Hook: Think of the singleton as the building's one reception desk: everyone can reach it, but only one desk is ever built.
Cheat Sheet:
new, but it is not enough by itself.enum or static holder.volatile matters for double-checked locking.Practice Tasks:
enum singleton and verify that both references are identical.