Skip to content
intermediatePhase 49 · Low-Level Design

Singleton Pattern

Ensure a class has only one instance with global access.

30m
0 problems
Topic Progress0%

Implementation Methods

Several ways to implement Singleton, each with different trade-offs.

Eager Initialization

public class DatabaseConnection {
    private static final DatabaseConnection INSTANCE = new DatabaseConnection();
    
    private DatabaseConnection() { }
    
    public static DatabaseConnection getInstance() {
        return INSTANCE;
    }
}
  • Simple, thread-safe
  • Instance created at class loading
  • Good if instance is always needed

Lazy Initialization

public class DatabaseConnection {
    private static DatabaseConnection instance;
    
    private DatabaseConnection() { }
    
    public static DatabaseConnection getInstance() {
        if (instance == null) {
            instance = new DatabaseConnection();
        }
        return instance;
    }
}
  • Created only when needed
  • NOT thread-safe

Synchronized Lazy

public class DatabaseConnection {
    private static DatabaseConnection instance;
    
    private DatabaseConnection() { }
    
    public static synchronized DatabaseConnection getInstance() {
        if (instance == null) {
            instance = new DatabaseConnection();
        }
        return instance;
    }
}
  • Thread-safe
  • Performance overhead from synchronization

Double-Checked Locking

public class DatabaseConnection {
    private static volatile DatabaseConnection instance;
    
    private DatabaseConnection() { }
    
    public static DatabaseConnection getInstance() {
        if (instance == null) {
            synchronized (DatabaseConnection.class) {
                if (instance == null) {
                    instance = new DatabaseConnection();
                }
            }
        }
        return instance;
    }
}
  • Thread-safe, no sync after initialization
  • Uses volatile for memory visibility

Bill Pugh Singleton

public class DatabaseConnection {
    private DatabaseConnection() { }
    
    private static class Holder {
        private static final DatabaseConnection INSTANCE = 
            new DatabaseConnection();
    }
    
    public static DatabaseConnection getInstance() {
        return Holder.INSTANCE;
    }
}
  • Lazy, thread-safe, no synchronization
  • Best approach in most cases

Thread Safety

Thread safety is critical for Singleton in multi-threaded environments.

The Problem

Thread A                     Thread B
────────                     ────────
check if instance == null    
→ true                       
                             check if instance == null
                             → true
create new instance          
                             create new instance
                             
Two instances created! ❌

Solutions Comparison

Method Thread-Safe Lazy Performance
Eager Fast
Synchronized Slow
Double-Checked Fast after init
Bill Pugh Fast
Enum Fast

Enum Singleton

public enum DatabaseConnection {
    INSTANCE;
    
    private Connection connection;
    
    DatabaseConnection() {
        this.connection = createConnection();
    }
    
    public Connection getConnection() {
        return connection;
    }
}

// Usage
Connection conn = DatabaseConnection.INSTANCE.getConnection();
  • Thread-safe by JVM guarantee
  • Handles serialization automatically
  • Prevents reflection attacks

Testing Singleton

// Problem: Singleton makes testing hard
public class OrderService {
    private final DatabaseConnection db = DatabaseConnection.getInstance();
    
    // Can't mock db in tests!
}

// Solution: Dependency Injection
public class OrderService {
    private final DatabaseConnection db;
    
    public OrderService(DatabaseConnection db) {
        this.db = db;
    }
    
    // Can inject mock in tests
}

// In production: inject singleton
OrderService service = new OrderService(DatabaseConnection.getInstance());

// In test:
OrderService service = new OrderService(mockDb);

Singleton Anti-Patterns

  1. Global state: Singleton is global state, hard to reason about
  2. Hidden dependencies: Classes secretly depend on singleton
  3. Testing difficulty: Can't mock without DI
  4. Tight coupling: Classes coupled to singleton implementation
  5. Lifetime management: Hard to control when singleton is created/destroyed

When to Use

Singleton is often overused. Understanding when it's appropriate is crucial.

Legitimate Use Cases

Use Case Why Singleton
Database connection pool Shared pool across application
Thread pool Single thread pool managing threads
Configuration manager Single source of truth for config
Cache Shared cache across components
Logger Single logging instance

When NOT to Use Singleton

Situation Why Not
Just for convenience Use DI instead
To share state Use dependency injection
For database access Use repository pattern
For any service Use DI container

Singleton vs Dependency Injection

// Singleton: hidden dependency
public class OrderService {
    private Database db = Database.getInstance(); // Hidden!
    
    public void createOrder(Order order) {
        db.save(order); // Where does db come from?
    }
}

// Dependency Injection: explicit dependency
public class OrderService {
    private final Database db;
    
    public OrderService(Database db) { // Explicit!
        this.db = db;
    }
    
    public void createOrder(Order order) {
        db.save(order); // Clear dependency
    }
}

Modern Alternative: DI Container

// Spring/Guice manage singleton scope
@Service  // Singleton scope by default
public class DatabaseService {
    public Connection getConnection() { ... }
}

@Service
public class OrderService {
    private final DatabaseService db;
    
    @Autowired
    public OrderService(DatabaseService db) {
        this.db = db; // Injected by container
    }
}

Decision Guide

Do you need exactly one instance?
├── Yes: Is it for infrastructure (connection pool, thread pool)?
│   └── Yes: Singleton is OK
├── Yes: Is it for business logic?
│   └── Yes: Use DI with singleton scope
└── No: Don't use Singleton

Can you use DI container?
├── Yes: Use DI with singleton scope
└── No: Consider Singleton implementation carefully

Practice Problems

0/3solved
Design Singleton Pattern System

Design a scalable Singleton Pattern system. Cover high-level architecture, data model, and API design.

Solution
// Complete system design:
// - Functional + Non-functional requirements
// - Capacity estimation
// - Data model (SQL/NoSQL choice)
// - API endpoints
// - Component architecture
// - Scaling strategy
// - Monitoring & reliability
Singleton Pattern Scaling

How would you scale Singleton Pattern to handle 10x the current load? Identify bottlenecks and solutions.

Solution
// Scaling approach:
// 1. Load balancing
// 2. Database sharding/replication
// 3. Cache layer (Redis)
// 4. CDN for static assets
// 5. Async processing (queues)
// 6. Microservices decomposition
Singleton Pattern Failure Modes

Analyze potential failure modes for Singleton Pattern and design mitigation strategies.

Solution
// Failure mitigation:
// 1. Redundancy (multi-AZ)
// 2. Circuit breakers
// 3. Retry with backoff
// 4. Dead letter queues
// 5. Health checks
// 6. Graceful degradation

Quiz

1. What is the Singleton pattern?

Question 1 options

2. What is the Bill Pugh Singleton approach?

Question 2 options

3. Why is Singleton considered an anti-pattern?

Question 3 options

4. What is the modern alternative to Singleton?

Question 4 options

5. When is Singleton appropriate?

Question 5 options

Flashcards

Question

What is the Singleton pattern?

Answer

Ensures a class has only one instance and provides a global point of access. Used for shared resources like connection pools.

Question

What is the best Singleton implementation?

Answer

Bill Pugh Singleton using static inner class holder. Lazy, thread-safe, no synchronization overhead.

Question

Why is Singleton considered an anti-pattern?

Answer

Creates global state, hidden dependencies, tight coupling, and testing difficulties. DI with singleton scope is preferred.

Question

Singleton vs DI with singleton scope?

Answer

Singleton: hidden dependency, global state. DI: explicit dependencies, testable, loose coupling. DI is preferred.

Question

When to use Singleton?

Answer

For infrastructure components that genuinely need one instance: connection pools, thread pools, configuration managers, caches.

Revision Notes

Key Takeaways

  • 1.Singleton ensures one instance with global access
  • 2.Bill Pugh Singleton is the recommended implementation
  • 3.Singleton creates global state and hidden dependencies
  • 4.DI with singleton scope is the modern alternative
  • 5.Use Singleton only for genuine infrastructure needs

Interview Tips

  • Explain when Singleton is appropriate vs when to use DI
  • Discuss thread safety concerns in Singleton implementation
  • Mention the testing difficulties caused by Singleton
  • Show how DI container achieves singleton scope without global state

Cheat Sheet

Singleton Pattern - Cheat Sheet

Implementation Methods:

Method Thread-Safe Lazy Best For
Eager Always needed
Synchronized Simple cases
Double-Checked Performance
Bill Pugh Most cases
Enum Serialization

Bill Pugh (Recommended):

private static class Holder {
    static final INSTANCE = new Singleton();
}

Problems:

  • Global state
  • Hidden dependencies
  • Testing difficulty
  • Tight coupling

Modern Alternative:
DI container with singleton scope

  • Explicit dependencies
  • Testable
  • Loose coupling