Java Singleton Pattern
Creational pattern ensuring only one instance of a class exists
java (1.0+)
2025-11-03
singleton
design-pattern
creational
Description
The Singleton pattern ensures that a class has only one instance and provides a global point of access to it. It’s useful when exactly one object is needed to coordinate actions across the system.
Key Characteristics
- Single instance: Only one instance of the class exists
- Global access: Provides a global point of access
- Lazy initialization: Instance created when first needed (optional)
- Thread safety: Must be safe in multithreaded environments
Implementation Approaches
- Eager initialization: Instance created at class loading time
- Lazy initialization: Instance created on first access
- Double-checked locking: Thread-safe lazy initialization
- Bill Pugh solution: Uses inner static class (recommended)
- Enum singleton: Simplest and most thread-safe
When to Use
- Need exactly one instance of a class
- Global access point needed
- Resource management (database connections, file systems)
- Logging, configuration, caching
Thread Safety Considerations
- Simple lazy initialization is NOT thread-safe
- Use synchronization or double-checked locking
- Enum singleton is inherently thread-safe
- Bill Pugh solution is thread-safe without synchronization overhead
Code
// Eager initialization (thread-safe)public class EagerSingleton { private static final EagerSingleton instance = new EagerSingleton(); private EagerSingleton() { // Private constructor prevents instantiation } public static EagerSingleton getInstance() { return instance; }}// Lazy initialization (NOT thread-safe)public class LazySingleton { private static LazySingleton instance; private LazySingleton() {} public static LazySingleton getInstance() { if (instance == null) { instance = new LazySingleton(); } return instance; }}// Thread-safe lazy initialization with synchronizedpublic class SynchronizedSingleton { private static SynchronizedSingleton instance; private SynchronizedSingleton() {} public static synchronized SynchronizedSingleton getInstance() { if (instance == null) { instance = new SynchronizedSingleton(); } return instance; }}// Double-checked locking (thread-safe)public class DoubleCheckedSingleton { private static volatile DoubleCheckedSingleton instance; private DoubleCheckedSingleton() {} public static DoubleCheckedSingleton getInstance() { if (instance == null) { synchronized (DoubleCheckedSingleton.class) { if (instance == null) { instance = new DoubleCheckedSingleton(); } } } return instance; }}// Bill Pugh solution (recommended - thread-safe, lazy)public class BillPughSingleton { private BillPughSingleton() {} private static class SingletonHelper { private static final BillPughSingleton instance = new BillPughSingleton(); } public static BillPughSingleton getInstance() { return SingletonHelper.instance; }}// Enum singleton (simplest, thread-safe, serializable)public enum EnumSingleton { INSTANCE; public void doSomething() { // Singleton methods here }}
// Eager singletonEagerSingleton eager1 = EagerSingleton.getInstance();EagerSingleton eager2 = EagerSingleton.getInstance();System.out.println(eager1 == eager2); // true - same instance// Lazy singleton (not thread-safe)LazySingleton lazy1 = LazySingleton.getInstance();LazySingleton lazy2 = LazySingleton.getInstance();System.out.println(lazy1 == lazy2); // true - same instance// Thread-safe singletonSynchronizedSingleton sync1 = SynchronizedSingleton.getInstance();SynchronizedSingleton sync2 = SynchronizedSingleton.getInstance();System.out.println(sync1 == sync2); // true// Double-checked singletonDoubleCheckedSingleton dcs1 = DoubleCheckedSingleton.getInstance();DoubleCheckedSingleton dcs2 = DoubleCheckedSingleton.getInstance();System.out.println(dcs1 == dcs2); // true// Bill Pugh singleton (recommended)BillPughSingleton bp1 = BillPughSingleton.getInstance();BillPughSingleton bp2 = BillPughSingleton.getInstance();System.out.println(bp1 == bp2); // true// Enum singleton (simplest)EnumSingleton enum1 = EnumSingleton.INSTANCE;EnumSingleton enum2 = EnumSingleton.INSTANCE;System.out.println(enum1 == enum2); // trueenum1.doSomething();// In multithreaded environmentExecutorService executor = Executors.newFixedThreadPool(10);for (int i = 0; i < 10; i++) { executor.submit(() -> { BillPughSingleton instance = BillPughSingleton.getInstance(); System.out.println("Thread: " + Thread.currentThread().getName() + ", Instance: " + instance); });}executor.shutdown();
Comments
No comments yet. Be the first to comment!
Please login to leave a comment.