designpatterns/creational booknotes
Singleton pattern ensure that a class has only one instance, while providing a global access point to this instance.

Structure

Drawbacks of the Singleton Design Pattern | Baeldung
Applicability
Use the Singleton pattern when a class in your program should have just a single instance available to all clients; for example, a single data- base object shared by different parts of the program.
Examples
Basic Singleton Implementation (Lazy Initialization, Thread-Unsafe)
class DatabaseManager {
private static DatabaseManager instance;
// Private constructor prevents instantiation from other classes
private DatabaseManager() {
System.out.println("DatabaseManager initialized.");
}
// Static method to get the single instance
public static DatabaseManager getInstance() {
if (instance == null) {
instance = new DatabaseManager();
}
return instance;
}
public void connect() {
System.out.println("Connected to the database.");
}
}
// Client Code
public class SingletonExample {
public static void main(String[] args) {
DatabaseManager db1 = DatabaseManager.getInstance();
db1.connect();
DatabaseManager db2 = DatabaseManager.getInstance();
db2.connect();
System.out.println(db1 == db2); // Output: true (Both are the same instance)
}
}Thread-Safe Singleton (Synchronized Method)
class DatabaseManager {
private static DatabaseManager instance;
private DatabaseManager() {
System.out.println("DatabaseManager initialized.");
}
public static synchronized DatabaseManager getInstance() { // synchronized ensures thread safety
if (instance == null) {
instance = new DatabaseManager();
}
return instance;
}
}Bill Pugh Singleton (Lazy + Efficient)
class DatabaseManager {
private DatabaseManager() {
System.out.println("DatabaseManager initialized.");
}
private static class SingletonHelper {
private static final DatabaseManager INSTANCE = new DatabaseManager();
}
public static DatabaseManager getInstance() {
return SingletonHelper.INSTANCE;
}
}DCL Singleton Implementation
class DatabaseManager {
private static volatile DatabaseManager instance; // Volatile ensures visibility across threads
private DatabaseManager() {
System.out.println("DatabaseManager initialized.");
}
public static DatabaseManager getInstance() {
if (instance == null) { // First check (No locking)
synchronized (DatabaseManager.class) { // Lock only the first time
if (instance == null) { // Second check (Ensures only one instance)
instance = new DatabaseManager();
}
}
}
return instance;
}
}
// Client Code
public class DCLSingletonExample {
public static void main(String[] args) {
DatabaseManager db1 = DatabaseManager.getInstance();
DatabaseManager db2 = DatabaseManager.getInstance();
System.out.println(db1 == db2); // Output: true (Same instance)
}
}Enum Singleton
enum DatabaseManager {
INSTANCE; // Single instance
// Constructor (called only once)
DatabaseManager() {
System.out.println("DatabaseManager initialized.");
}
public void connect() {
System.out.println("Connected to the database.");
}
}
// Client Code
public class EnumSingletonExample {
public static void main(String[] args) {
DatabaseManager db1 = DatabaseManager.INSTANCE;
db1.connect();
DatabaseManager db2 = DatabaseManager.INSTANCE;
db2.connect();
System.out.println(db1 == db2); // Output: true (Same instance)
}
}Comparison of Singleton Implementation Methods in Java
| Singleton Type | Thread-Safe? | Lazy Initialization? | Performance | Reflection-Safe? | Serialization-Safe? | Complexity | Best Use Case |
|---|---|---|---|---|---|---|---|
| Basic (Lazy Initialization) | β No | β Yes | β‘ Fast | β No | β No | β Simple | Single-threaded apps |
| Synchronized Method | β Yes | β Yes | π’ Slow (due to locking) | β No | β No | ββ Medium | Multi-threaded apps (small-scale) |
| Double-Checked Locking (DCL) | β Yes | β Yes | β‘ Fast (locks only once) | β No | β No | βββ Moderate | High-performance multi-threaded apps |
| Bill Pugh Singleton (Static Inner Class) | β Yes | β Yes | β‘ Fast | β No | β No | βββ Moderate | Best alternative to DCL |
| Enum Singleton (Recommended) | β Yes | β No (Eager) | β‘ Fast | β Yes | β Yes | ββ Simple | Best for all cases (Preferred approach) |
Tip
Lazy Initialization
The object is created only when it is needed (i.e., when itβs accessed for the first time).Eager Initialization
The object is created as soon as the class is loaded, even if it is not used immediately.