Back to Design Patterns
Creational Pattern

Singleton Pattern

Ensure a class has only one instance and provide a global point of access to it.

Beginner Friendly8 min read

What is the Singleton Pattern?

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.

!Problem It Solves

Multiple Instances Problem

Without Singleton, every time you create an object, you get a new instance. This can cause problems when:

  • → Multiple database connections waste resources
  • → Different configuration objects lead to inconsistency
  • → Multiple logger instances create file conflicts
  • → Shared state management becomes difficult

Example Without Singleton

// 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

How It Works

1

Private Constructor

Prevents outside code from creating new instances using new

2

Static Instance

Stores the single instance as a static variable inside the class

3

Public Accessor

Provides a static method (getInstance) to access the instance

Implementation

// 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");
    }
}

When to Use Singleton

Configuration Management

Store application settings that should be consistent across the entire application

AppConfig, EnvironmentSettings

Resource Pooling

Manage expensive resources like database connections or thread pools

ConnectionPool, ThreadPool

Logging

Centralize logging operations to avoid file conflicts and maintain consistency

Logger, FileLogger

Caching

Maintain a single cache instance to ensure data consistency

CacheManager, MemoryCache

Pros & Cons

Advantages

  • Controlled access to sole instance
  • Reduced memory footprint
  • Global access point
  • Lazy initialization possible

Disadvantages

  • Violates Single Responsibility Principle
  • Can be difficult to unit test
  • Requires special care in multithreaded environments
  • Can create tight coupling

Real-World Examples

Spring Framework (Java)

Spring beans are Singleton by default, meaning only one instance per Spring IoC container

Python logging module

The logging.getLogger(name) returns the same logger instance for the same name

Redux Store (JavaScript)

Redux maintains a single store instance for the entire application state

What's Next?

Now that you understand Singleton, explore other Creational patterns: