The Singleton pattern ensures a class has exactly one instance and provides a global access point to it. It is one of the most widely recognized creational patterns, used whenever a single shared object must coordinate actions across an entire application.

Intent and Motivation

Intent: Guarantee that a class is instantiated at most once and provide a single, well-known access point for that instance.

Motivation: Some resources are inherently singular — configuration registries, connection pools, logging sinks, or hardware device drivers. Creating multiple instances would waste memory, cause inconsistent state, or break coordination. Singleton centralizes control so every part of the system references the same object.

Without Singleton, developers might pass instances through constructors or dependency injection containers. When a truly global singleton is appropriate, the pattern prevents accidental duplicate creation through a controlled factory method.

Structure (UML-like)

  ┌─────────────────────────┐
│       Singleton         │
├─────────────────────────┤
│ - instance: Singleton   │  (static, holds the sole instance)
├─────────────────────────┤
│ - Singleton()           │  (private constructor)
│ + getInstance():        │
│   Singleton             │  (static factory method)
│ + businessMethod()      │
└─────────────────────────┘
  

Participants:

  • Singleton — defines getInstance() and holds the static reference; constructor is private.
  • Client — calls getInstance() instead of new Singleton().

Java Example

  public final class DatabaseConnection {
    private static volatile DatabaseConnection instance;

    private DatabaseConnection() {
        // Expensive initialization (connection pool, etc.)
    }

    public static DatabaseConnection getInstance() {
        if (instance == null) {
            synchronized (DatabaseConnection.class) {
                if (instance == null) {
                    instance = new DatabaseConnection();
                }
            }
        }
        return instance;
    }

    public void query(String sql) {
        System.out.println("Executing: " + sql);
    }
}

// Usage
DatabaseConnection db1 = DatabaseConnection.getInstance();
DatabaseConnection db2 = DatabaseConnection.getInstance();
System.out.println(db1 == db2); // true
  

The double-checked locking idiom with volatile is the standard thread-safe lazy initialization approach in Java.

JavaScript Example

  const Singleton = (function () {
  let instance;

  function createInstance() {
    return {
      config: { theme: 'dark', locale: 'en-US' },
      get(key) { return this.config[key]; },
      set(key, value) { this.config[key] = value; }
    };
  }

  return {
    getInstance() {
      if (!instance) {
        instance = createInstance();
      }
      return instance;
    }
  };
})();

const a = Singleton.getInstance();
const b = Singleton.getInstance();
console.log(a === b); // true
a.set('theme', 'light');
console.log(b.get('theme')); // 'light'
  

In modern JavaScript, ES module singletons (a module that exports one shared object) often replace explicit pattern code because modules are evaluated once per runtime.

Real-World Use Cases

Framework / System Usage
Spring Framework @Scope("singleton") is the default bean scope — one instance per container.
java.lang.Runtime Runtime.getRuntime() exposes the single JVM runtime object.
Android ActivityManager, LocationManager — system services accessed via singleton getters.
Redux (JavaScript) The store is a single global state container, conceptually a singleton.
Log4j / SLF4J Logger factories often return shared logger instances per class name.

Pros and Cons

Pros Cons
Controlled access to a sole instance Violates Single Responsibility Principle (class manages itself + business logic)
Lazy initialization saves resources Hard to unit test (global state persists between tests)
Global access simplifies coordination Hides dependencies — callers use getInstance() instead of injection
Thread-safe variants prevent race conditions Can become a “god object” accumulating too many responsibilities
Reduces memory for expensive objects Tight coupling to the concrete class

When to Use vs When NOT to Use

Use when:

  • Exactly one instance must exist (configuration manager, audit trail, device driver).
  • The instance must be accessible from many unrelated parts of the codebase.
  • Lazy initialization is important (object is expensive to create and may never be needed).

Do NOT use when:

  • You can achieve the same result with dependency injection (preferred in modern apps).
  • The class has no reason to be global — pass the instance explicitly.
  • You need multiple instances in tests or multi-tenant environments.
  • Concurrency requirements make locking overhead unacceptable (consider enum singleton or DI).

Common Mistakes

  1. Forgetting thread safety — two threads can create two instances without synchronization.
  2. Allowing cloning or serializationclone() or readObject() can bypass the single instance; override and block them.
  3. Eager initialization when lazy is needed — static field initialization runs at class load, not on first use.
  4. Overusing Singleton — not every shared object needs this pattern; DI containers manage lifecycles better.
  5. Subclassing a Singleton — subclasses each get their own static instance, breaking the “one instance” guarantee unless carefully designed.
  • Factory Method / Abstract Factory — can ensure only one instance of each product type is created.
  • Facade — often implemented as a singleton because a single facade simplifies subsystem access.
  • Monostate — alternative that shares state across instances rather than sharing the instance itself.
  • Dependency Injection — modern replacement that provides controlled single-instance wiring without global accessors.

Summary

Singleton is powerful when a resource is truly singular, but it is also one of the most abused patterns. Prefer dependency injection and module-level singletons in modern applications, and reserve explicit Singleton implementations for cases where global coordination is an explicit architectural requirement.