The Singleton Pattern ensures a class has only one instance and provides a global point of access to it.
The Singleton Pattern restricts instantiation of a class to a single object by:
- Making the constructor private
- Providing a static method that returns the single instance
- Storing the instance in a static variable
- Private Constructor: Prevents external instantiation
- Static Instance: Holds the one and only instance
- Static Access Method:
getInstance()provides global access to the instance - Lazy Initialization: Instance is created only when first requested (in some implementations)
Basic implementation of the Singleton pattern with lazy initialization.
- Singleton.java - Simple singleton implementation
Note: This implementation is NOT thread-safe. In a multithreaded environment, multiple instances could be created.
Demonstrates various thread-safe implementations of the Singleton pattern:
- BasicSingleton.java - Synchronized getInstance() method
- EagerlySingleton.java - Eager initialization (thread-safe by design)
- DoubleLockSingleton.java - Double-checked locking pattern
public static synchronized Singleton getInstance() {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}- Pros: Simple, thread-safe
- Cons: Synchronization overhead on every call (only needed on first call)
private static Singleton uniqueInstance = new Singleton();
public static Singleton getInstance() {
return uniqueInstance;
}- Pros: Simple, thread-safe, no synchronization overhead
- Cons: Instance created even if never used, no lazy initialization
private volatile static Singleton uniqueInstance;
public static Singleton getInstance() {
if (uniqueInstance == null) {
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}- Pros: Thread-safe, minimal synchronization overhead, lazy initialization
- Cons: More complex, requires
volatilekeyword (Java 5+)
private Singleton() {}
private static class SingletonHelper {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHelper.INSTANCE;
}- Pros: Thread-safe, lazy initialization, no synchronization, simple
- Cons: None (this is the recommended approach)
From the parent directory of Singleton:
javac -d out Singleton/SimpleSingleton/*.java
javac -d out Singleton/Multithreading/*.javaThese classes are pattern implementations without a main method and cannot be run directly. They are intended to be used as library classes in a larger application.
- Controlled Access: Ensures only one instance exists
- Reduced Namespace Pollution: Better than global variables
- Permits Refinement: Can subclass singleton (though not common)
- Lazy Initialization: Can defer creation until needed (some implementations)
- Global Access: Accessible from anywhere in the application
- Global State: Can make code harder to test and maintain
- Hidden Dependencies: Dependencies on singleton are not obvious
- Difficult to Test: Hard to mock or replace in unit tests
- Violates Single Responsibility: Manages its own lifecycle and business logic
- Concurrency Issues: Requires careful implementation in multithreaded environments
- Subclassing Challenges: Difficult to extend
Use the Singleton Pattern when:
- There must be exactly one instance of a class
- The instance must be accessible from multiple points in the application
- The single instance should be extensible by subclassing
Common use cases:
- Configuration managers
- Connection pools
- Thread pools
- Caches
- Logging
- Device drivers
-
Dependency Injection: Pass dependencies explicitly instead of using singletons
-
Static Utility Classes: For stateless utilities (Math, Collections)
-
Enum Singleton (Java-specific): Thread-safe, serialization-safe, prevents reflection attacks
public enum Singleton { INSTANCE; // methods here }
Standard singleton implementations can be broken during deserialization. To prevent this, implement:
protected Object readResolve() {
return getInstance();
}Reflection can be used to access private constructors. Enum singletons are immune to this.
Multiple classloaders can create multiple instances. Be aware in complex applications.
The Singleton Pattern demonstrates:
- Encapsulation: Hides the creation logic
- Single Responsibility (debatable): Manages both its instance and business logic