Ensure a class has only one instance and provide a global point of access to it.
The Singleton pattern is a creational design pattern that restricts the instantiation of a class to a single instance. This is useful when exactly one object is needed to coordinate actions across the system.
Think of it like having only one president in a country, one database connection pool in an application, or one configuration manager that all parts of your system can access.
Key Idea: Control object creation to ensure only one instance exists, and provide a global access point to that instance.
Without Singleton, every time you create an object, you get a new instance. This can cause problems when:
// Problem: Multiple instances DatabaseConnection db1 = new DatabaseConnection(); DatabaseConnection db2 = new DatabaseConnection(); // db1 and db2 are DIFFERENT objects (wasteful!) // This creates multiple expensive connections // Uses more memory and resources unnecessarily
Prevents outside code from creating new instances using new
Stores the single instance as a static variable inside the class
Provides a static method (getInstance) to access the instance
// Thread-Safe Singleton with Double-Checked Locking
public class DatabaseConnection {
// volatile ensures visibility across threads
private static volatile DatabaseConnection instance;
private String connectionUrl;
// Private constructor prevents instantiation
private DatabaseConnection() {
// Expensive initialization
this.connectionUrl = "jdbc:mysql://localhost:3306/mydb";
System.out.println("Database connection initialized");
}
// Thread-safe getInstance with double-checked locking
public static DatabaseConnection getInstance() {
if (instance == null) { // First check (no locking)
synchronized (DatabaseConnection.class) {
if (instance == null) { // Second check (with locking)
instance = new DatabaseConnection();
}
}
}
return instance;
}
public void executeQuery(String query) {
System.out.println("Executing: " + query);
}
}
// Usage Example
public class Application {
public static void main(String[] args) {
// Both variables point to the same instance
DatabaseConnection db1 = DatabaseConnection.getInstance();
DatabaseConnection db2 = DatabaseConnection.getInstance();
System.out.println(db1 == db2); // Output: true
db1.executeQuery("SELECT * FROM users");
}
}Store application settings that should be consistent across the entire application
AppConfig, EnvironmentSettingsManage expensive resources like database connections or thread pools
ConnectionPool, ThreadPoolCentralize logging operations to avoid file conflicts and maintain consistency
Logger, FileLoggerMaintain a single cache instance to ensure data consistency
CacheManager, MemoryCacheSpring beans are Singleton by default, meaning only one instance per Spring IoC container
The logging.getLogger(name) returns the same logger instance for the same name
Redux maintains a single store instance for the entire application state