Singleton Design Pattern: 7 Powerful Ways to Implement It
Akshay Kumar
Tech Lead @ Noventiq | JAVA, Mobile, Web | React & React Native | AI and ML | AWS Certified
The Singleton design pattern is one of the most widely used patterns in software development. It ensures that a class has only one instance and provides a global point of access to it. This pattern is especially useful in scenarios like database connections, logging, caching, and configuration management, where multiple instances could lead to inconsistencies or resource overhead.
In this article, we will explore seven powerful ways to implement the Singleton pattern, discussing their advantages, disadvantages, and best-use cases.
Why Use the Singleton Pattern?
Before diving into the implementations, let’s quickly understand why the Singleton pattern is beneficial:
Now, let’s explore seven different ways to implement Singleton in Java.
1. Eager Initialization Singleton
Implementation:
public class EagerSingleton {
private static final EagerSingleton instance = new EagerSingleton();
private EagerSingleton() {}
public static EagerSingleton getInstance() {
return instance;
}
}
Pros:
1. Simple to implement. 2. Thread-safe without synchronization overhead.
Cons:
? Instance is created even if it’s never used, leading to resource wastage.
2. Lazy Initialization Singleton
Implementation:
public class LazySingleton {
private static LazySingleton instance;
private LazySingleton() {}
public static LazySingleton getInstance() {
if (instance == null) {
instance = new LazySingleton();
}
return instance;
}
}
Pros:
Saves memory by creating an instance only when needed.
Cons:
? Not thread-safe — multiple threads might create multiple instances.
3. Thread-Safe Singleton (Synchronized Method)
Implementation:
public class SynchronizedSingleton {
private static SynchronizedSingleton instance;
private SynchronizedSingleton() {}
public static synchronized SynchronizedSingleton getInstance() {
if (instance == null) {
instance = new SynchronizedSingleton();
}
return instance;
}
}
Pros:
Thread-safe due to synchronization.
Cons:
? Performance overhead due to synchronized method.
4. Double-Checked Locking Singleton
Implementation:
public class DoubleCheckedLockingSingleton {
private static volatile DoubleCheckedLockingSingleton instance;
private DoubleCheckedLockingSingleton() {}
public static DoubleCheckedLockingSingleton getInstance() {
if (instance == null) {
synchronized (DoubleCheckedLockingSingleton.class) {
if (instance == null) {
instance = new DoubleCheckedLockingSingleton();
}
}
}
return instance;
}
}
Pros:
Cons:
? Slightly complex implementation.
5. Bill Pugh Singleton (Best Approach)
Implementation:
public class BillPughSingleton {
private BillPughSingleton() {}
private static class SingletonHelper {
private static final BillPughSingleton INSTANCE = new BillPughSingleton();
}
public static BillPughSingleton getInstance() {
return SingletonHelper.INSTANCE;
}
}
Pros:
Cons:
? Slightly advanced concept for beginners.
6. Enum Singleton (Most Secure & Recommended)
Implementation:
public enum EnumSingleton {
INSTANCE;
public void someMethod() {
System.out.println("Using Enum Singleton");
}
}
Pros:
Cons:
? Cannot implement lazy initialization.
7. Using Java 8 Supplier (Functional Approach)
Implementation:
import java.util.function.Supplier;
public class SupplierSingleton {
private static final Supplier<SupplierSingleton> INSTANCE =
() -> SingletonHolder.INSTANCE;
private static class SingletonHolder {
private static final SupplierSingleton INSTANCE = new SupplierSingleton();
}
private SupplierSingleton() {}
public static SupplierSingleton getInstance() {
return INSTANCE.get();
}
}
Pros:
Cons:
? Slightly unconventional approach.
Conclusion
The Singleton pattern is essential for ensuring a single point of control in various applications. Each implementation comes with its own advantages and trade-offs:
Choosing the right approach depends on your project’s requirements. If thread safety and security are key concerns, Enum Singleton is highly recommended. If you prefer a lazy initialization without synchronization overhead, Bill Pugh Singleton is a great choice.
Let me know in the comments which Singleton implementation you prefer and why! Happy coding!