Design Patterns
🏗️ Design Patterns¶
Have you worked on any design patterns?¶
Yes, I have primarily worked with creational design patterns like Singleton and Factory. These patterns help in controlling object creation and improving code maintainability. In real-world applications, I have used Singleton for shared resources such as configuration management, logging, and database connections.
How does Singleton design pattern work?¶
The Singleton design pattern ensures that only one instance of a class exists throughout the application and provides a global access point to that instance.
Key Characteristics:¶
- The constructor is private to prevent external instantiation
- A static variable holds the single instance
- A public static method provides access to the instance
Basic Implementation (Lazy Initialization):¶
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
````
### Problem:
This implementation is not thread-safe. In a multithreaded environment, multiple threads can create multiple instances
simultaneously.
---
## Singleton in multithreading?
To make Singleton thread-safe, we need to handle concurrent access.
### Approach 1: Synchronized Method
```java
public static synchronized Singleton getInstance()
- Ensures thread safety
- But reduces performance because every call acquires a lock
Approach 2: Double-Checked Locking (Recommended)¶
public class Singleton {
private static volatile Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) { // First check
synchronized (Singleton.class) {
if (instance == null) { // Second check
instance = new Singleton();
}
}
}
return instance;
}
}
Why double check?¶
- First check avoids unnecessary locking
- Second check ensures only one instance is created
Why use volatile?¶
Without volatile, JVM may reorder instructions:
- Allocate memory
- Assign reference
- Initialize object
This can result in another thread accessing a partially constructed object.
Interview Tip:¶
Double-checked locking improves performance while maintaining thread safety.
Can Singleton be serialized?¶
Yes, a Singleton class can be serialized, but serialization can break the Singleton pattern.
What is serialization?¶
Serialization is the process of converting an object into a byte stream so that it can be:
- Stored in a file
- Sent over a network
- Cached for later use
Deserialization is the reverse process where the byte stream is converted back into an object.
How does serialization/deserialization break Singleton?¶
During deserialization, Java creates a new object instead of returning the existing instance.
Example:
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("file.ser"));
Singleton obj2 = (Singleton) ois.readObject();
Now:
- obj1 → original instance
- obj2 → new instance
This violates the Singleton principle.
How to fix it?¶
Solution: Implement readResolve()¶
How it works:¶
- During deserialization, JVM calls
readResolve() - Instead of returning the newly created object, it returns the existing Singleton instance
Additional Best Practice (Bill Pugh Singleton)¶
This is a cleaner and thread-safe approach:
public class Singleton {
private Singleton() {
}
private static class Helper {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return Helper.INSTANCE;
}
}
Advantages:¶
- Thread-safe without synchronization
- Lazy loading
- Better performance
Another Alternative: Enum Singleton (Safest)¶
Advantages:¶
- Automatically thread-safe
- Handles serialization internally
- Protects against reflection attacks
Common Interview Follow-ups¶
1. Can Singleton be broken using reflection?¶
Yes. Reflection can access the private constructor and create multiple instances.
Fix:¶
Add a check inside constructor:
2. Where is Singleton used in real projects?¶
- Logging frameworks
- Configuration managers
- Database connection pools
- Caching systems
3. When should you avoid Singleton?¶
- When unit testing is required (tight coupling)
- When state changes frequently
- When scalability is needed
Final Summary¶
- Singleton ensures a single instance
-
Must handle:
- Multithreading
- Serialization
- Reflection
-
Best implementations:
-
Double-checked locking
- Bill Pugh method
- Enum Singleton