Singleton Pattern
Singleton → ensure class has exactly one instance + provide global access point.
create()getInstance()process()- “I will apply Singleton Pattern here to encapsulate changes and satisfy Open/Closed principle.”
- “De-couples core execution from specific implementations.”
Singleton Pattern
Singleton Pattern
1. ONE-LINE IDEA
Singleton → ensure class has exactly one instance + provide global access point.
Examples: application config, shared logger, in-memory registry.
2. REQUIREMENTS
- One instance per JVM/classloader.
- Global access via
getInstance(). - Lazy or eager initialization.
- Thread-safe creation.
- Prevent duplicate instances through normal construction.
- Serialization/reflection considerations when strict uniqueness matters.
3. CORE ENTITIES
Singleton→ private constructor, static instance, public accessor.- Client → gets shared instance.
4. UML DIAGRAM
+----------------------------+
| Singleton |
+----------------------------+
| - instance: Singleton | {static}
+----------------------------+
| - Singleton() |
| + getInstance(): Singleton | {static}
+----------------------------+5. IMPLEMENTATION OPTIONS
Option A: Eager initialization
Java
public final class AppConfig {
private static final AppConfig INSTANCE = new AppConfig();
private AppConfig() {}
public static AppConfig getInstance() {
return INSTANCE;
}
}- Thread-safe class initialization.
- Simple.
- Instance created even if never used.
Option B: Lazy initialization — unsafe
Java
public final class AppConfig {
private static AppConfig instance;
private AppConfig() {}
public static AppConfig getInstance() {
if (instance == null) {
instance = new AppConfig();
}
return instance;
}
}Problem: Two threads can both see null → create two instances.
Never use this version in concurrent code.
Option C: Synchronized accessor
Java
public final class AppConfig {
private static AppConfig instance;
private AppConfig() {}
public static synchronized AppConfig getInstance() {
if (instance == null) {
instance = new AppConfig();
}
return instance;
}
}Thread-safe, but synchronization occurs on every call.
Option D: Double-checked locking
Java
public final class AppConfig {
private static volatile AppConfig instance;
private AppConfig() {}
public static AppConfig getInstance() {
if (instance == null) {
synchronized (AppConfig.class) {
if (instance == null) {
instance = new AppConfig();
}
}
}
return instance;
}
}- Lazy creation.
- Thread-safe with
volatile. - Avoids locking after initialization.
- More complex than necessary for most cases.
volatile prevents unsafe publication/reordering and ensures visibility.
Option E: Bill Pugh — initialization-on-demand holder
Java
public final class AppConfig {
private AppConfig() {}
private static class Holder {
private static final AppConfig INSTANCE = new AppConfig();
}
public static AppConfig getInstance() {
return Holder.INSTANCE;
}
}Good default for lazy Singleton in Java.
- Lazy initialization.
- Thread-safe through JVM class initialization.
- No explicit synchronization.
Option F: Enum Singleton — strongest simple option
Java
public enum AppConfig {
INSTANCE;
public void printConfig() {
System.out.println("Config loaded");
}
}Usage:
Java
AppConfig.INSTANCE.printConfig();- Thread-safe.
- Serialization-safe by Java enum rules.
- Strong protection against reflective construction.
- Not lazy in the same way as holder idiom; enum initialization occurs when enum class initializes.
6. COMPLETE RUNNABLE EXAMPLE
Use holder idiom:
Java
public final class Singleton {
private Singleton() {}
private static class Holder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return Holder.INSTANCE;
}
public void execute() {
System.out.println("Singleton executing");
}
}
public class Main {
public static void main(String[] args) {
Singleton first = Singleton.getInstance();
Singleton second = Singleton.getInstance();
first.execute();
System.out.println(first == second);
}
}Output:
Singleton executing
true== checks object identity, confirming both references point to same instance.
7. THREAD SAFETY
| Approach | Thread-safe? | Lazy? |
|---|---|---|
| Eager static field | Yes | No |
| Naive lazy | No | Yes |
| Synchronized accessor | Yes | Yes |
Double-checked locking + volatile | Yes | Yes |
| Holder idiom | Yes | Yes |
| Enum | Yes | On enum initialization |
8. INTERVIEW QUESTIONS
Q: Why private constructor?
Prevents normal external instantiation using new.
Q: Why static instance?
Instance belongs to class, not individual objects.
Q: Why volatile in double-checked locking?
Without it, unsafe publication/reordering can expose incompletely initialized object.
Q: Can reflection break Singleton?
Private constructors can often be accessed reflectively. Enum Singleton has stronger protection against reflective instantiation.
Q: Can serialization create another instance?
Ordinary serializable Singleton may deserialize into another object unless readResolve() returns canonical instance. Enum serialization handles identity automatically.
Q: Is Singleton always good?
No. Global mutable state creates hidden dependencies, testing difficulty, and concurrency risks.
Q: Singleton vs static class?
Singleton is an object → can implement interfaces, be passed as dependency, and participate in polymorphism. Static methods aren't instance-polymorphic.
Q: Singleton vs Dependency Injection?
Singleton controls instance creation/access. DI controls dependency construction and wiring. DI container can manage singleton-scoped objects without implementing Singleton Pattern manually.
9. REAL-WORLD USE
- Shared immutable config.
- Logger registry.
- Process-wide metrics registry.
- Cache manager, when one shared instance is intentional.
Avoid assuming Singleton automatically means one instance across multiple JVMs, containers, or classloaders. It normally means one instance per defining classloader.
10. QUICK REVISION
- Private constructor.
- Static instance.
- Public static accessor.
- Thread safety matters.
- Holder idiom → strong lazy default.
- Enum → simplest robust Singleton.
- Global mutable state → testing + coupling risks.
11. MEMORY TRICK
One class → one instance → one access point.