Interview Tip: Show all 3 versions — basic (broken), synchronized (slow), double-checked locking (production). Then mention enum singleton.
Ensures a class has only one instance throughout the application.
Constructor is private — so no one can do new MyClass() from outside.
public class Singleton {
private static Singleton instance;
private Singleton() { // private constructor — key!
System.out.println("Singleton created");
}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton(); // ❌ Two threads can enter here simultaneously
}
return instance;
}
}Problem: Two threads can both see instance == null and both create instances → breaks singleton.
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}Problem: synchronized on every call — performance hit even after instance is created.
public class Singleton {
private static volatile Singleton instance; // volatile is critical!
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) { // first check — no sync needed
synchronized (Singleton.class) {
if (instance == null) { // second check — inside sync
instance = new Singleton();
}
}
}
return instance;
}
}Why volatile? Without it, CPU instruction reordering can cause a partially constructed object to be seen by another thread.
public enum Singleton {
INSTANCE;
public void doSomething() {
System.out.println("Doing work in singleton");
}
}
// Usage
Singleton.INSTANCE.doSomething();Benefits:
- Thread-safe by default
- Prevents reflection attacks (can't instantiate enum via reflection)
- Handles serialization automatically
public class Singleton {
private Singleton() {}
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE; // loaded only when first accessed
}
}Why it works: Inner class is loaded lazily by JVM — only when getInstance() is called. JVM class loading is thread-safe.
privateconstructor → preventsnew Singleton()from anywhere else- No
publicorprotectedconstructor - Subclassing is also prevented (can't extend a class with private constructor)
| Advantages | Disadvantages |
|---|---|
| Single shared instance | Hard to unit test (global state) |
| Saves memory | Tight coupling |
| Consistent state | Multi-threading needs care |
| Lazy or eager init | Violates Single Responsibility in some designs |
In Spring Boot, all beans are Singleton by default (per ApplicationContext).
@Service // → singleton by default
public class UserService { }
@Service
@Scope("prototype") // → new instance each time
public class ReportService { }