XREF Tech

$ less article.md

The Singleton Pattern: How It Works, Code Examples and Why It Is Controversial

A singleton is a class that allows exactly one instance of itself and gives the rest of the program one global way to reach it. The Gang of Four described it in 1994, and it remains the most disputed of their 23 design patterns. Many developers use it, many others avoid it, and Google’s testing blog once called singletons “pathological liars.” This guide covers how the pattern works, how to make it thread-safe in Java and C++, why it causes trouble, and what you can use instead.

What the Singleton Pattern Is and Where It Comes From

In general English, a “singleton” is a person or thing that occurs alone. In mathematics, it is a set with exactly one element. Software borrowed the idea through Design Patterns: Elements of Reusable Object-Oriented Software by Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides, the “Gang of Four” (GoF). The book was presented at OOPSLA 1994, published on October 21, 1994, and has sold more than 500,000 copies in 13 languages.

The GoF definition is short: “Ensure a class only has one instance, and provide a global point of access to it.” Singleton is a creational pattern, which means it controls how objects are created. Other GoF patterns such as Abstract Factory, Builder, Prototype, Facade and State are often implemented as singletons.

How a Singleton Works: The Four Building Blocks

Every classic implementation follows the same GoF recipe:

  1. A private static attribute holds the single instance.
  2. A public static accessor, usually getInstance() or instance(), is the only public way to get the object.
  3. Lazy initialization inside the accessor creates the instance on the first call. Every later call returns the same object.
  4. Private or protected constructors stop outside code from calling new.

C++ needs one more step. You have to disable the copy constructor and the assignment operator by making them private or = delete. If you leave them in, the compiler generates them, and callers can copy your “only” instance. Forgetting this step is a typical singleton bug.

How to Implement a Thread-Safe Singleton in Java and C++

Lazy initialization causes a race condition. If two threads call the accessor at the same moment, both can see “no instance yet” and both can create one. Each language solves this in its own way.

Java: from eager to enum

The eager singleton creates the instance in a private static final field when the class loads. It is simple and thread-safe, but the object exists even if nothing ever uses it. The synchronized lazy singleton marks the whole getInstance() method synchronized. That is correct, but every call pays for locking, even long after the object exists.

Double-checked locking checks first without a lock, then locks, then checks again:

public final class Config {
    private static volatile Config instance;   // volatile is mandatory
    private Config() {}

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

Without volatile, this code is broken. The compiler can reorder steps, so the reference can become visible to other threads before the constructor finishes. A second thread could then use a half-built object. This is the well-known “Double-Checked Locking is Broken” problem. volatile fixes it because it guarantees a happens-before ordering between the write and later reads.

The initialization-on-demand holder idiom, credited to Bill Pugh, avoids writing any synchronization code yourself:

public final class Config {
    private Config() {}
    private static class Holder {
        static final Config INSTANCE = new Config();
    }
    public static Config getInstance() {
        return Holder.INSTANCE;
    }
}

The JVM loads Holder only on the first call to getInstance(), and class loading is thread-safe by design. In Effective Java (2nd Edition), Joshua Bloch goes further and recommends a single-element enum as the best implementation. It gives you thread safety, correct serialization and protection against reflection attacks at no extra cost:

public enum IdFactory {
    INSTANCE;
    public long next() { /* ... */ return 0L; }
}

C++: the Meyers singleton

Scott Meyers popularized this version in More Effective C++. It uses a local static variable:

class Logger {
public:
    static Logger& instance() {
        static Logger s;          // initialized on first call
        return s;
    }
    Logger(const Logger&) = delete;
    Logger& operator=(const Logger&) = delete;
    void write(const std::string& msg);
private:
    Logger() = default;
};

Since C++11, the standard (§6.7 [stmt.dcl] p4) guarantees thread-safe initialization: if a second thread arrives while the variable is being initialized, it waits until initialization finishes. In C++03 there was no such guarantee. Compilers often used a plain flag check with no critical section. GCC has supported these “magic statics” since version 4.3, and Visual Studio since VS 2015. Because initialization waits for the first call, the Meyers singleton also avoids the static initialization order fiasco, where global objects in different translation units depend on each other before they exist. If you need a ready-made template, Boost ships one in boost/serialization/singleton.hpp.

One limit: only creating the instance is thread-safe. If several threads read and write the logger’s members afterward, you still need your own locks.

Which implementation to choose

Variant Language Lazy? Thread-safe? Catch
Eager static field Java No Yes Instance exists even if unused
Synchronized method Java Yes Yes Lock cost on every call
Double-checked locking Java Yes Only with volatile Easy to get wrong
Holder idiom Java Yes Yes (class loading) No serialization protection built in
Enum Java No Yes Cannot extend another class
Meyers singleton C++11+ Yes Initialization only Member access still needs locks

When You Should Use the Singleton Design Pattern

Typical uses involve a shared resource that should exist only once: a database connection pool, a logger, a configuration manager, a thread pool or a cache. The logger is the classic example. Many components write to one file, so one object seems natural.

The strongest case is when the model really contains exactly one of something, such as a registry office, a global timer or a unique ID factory. A singleton can also make sense when an object is tied to a single piece of hardware, such as an OpenGL context or a graphics driver. If you do use one, do it on purpose. Block copying and assignment, and expose the singleton through an interface (an abstract class) so you can replace the implementation later.

Why Developers Avoid Singletons

Rainer Grimm’s article on thread-safe singleton initialization has been read more than 300,000 times. In his Twitter poll of about 150 developers, 59% said they use singletons and 41% said they do not. Grimm estimates that real usage is closer to 80% once you count developers who use them without realizing it. The criticism is specific:

  • It is a global variable with a new name. The pattern does not remove global state. It wraps it in a class.
  • Hidden dependencies. In Miško Hevery’s 2008 Google Testing Blog post, singletons are “pathological liars” because method signatures do not reveal them. A call to void place() tells you nothing about the Logger::instance().write(...) inside it. You have to read the implementation to find the coupling.
  • SOLID violations. The class controls its own creation and does its real job, which breaks Single Responsibility. Callers depend on a concrete class rather than an abstraction, which breaks Dependency Inversion.
  • Hard to test. State carries over from one test to the next, the instance is hard to mock, and side effects like file I/O are forced on every test. In one medical-device project described by Arnaud Becheler, the codebase was full of singletons and testing became impossible because every test pulled in the whole system.
  • “Only one, forever” rarely holds. When the business suddenly needs two log files or two database connections, every getInstance() call becomes a refactoring site.
  • Fan-in risk. Many classes depend on the same singleton. This high afferent coupling makes it the riskiest class in the codebase to change.
  • Concurrency. Shared mutable state is hard to synchronize on multi-core machines and across processes.

Common Myths About Singletons

  • Myth: “Double-checked locking is always broken.” In Java it was broken without volatile. With a volatile field, it is correct, though the holder idiom and the enum are simpler.

Alternatives to the Singleton Design Pattern

Dependency injection (DI) passes dependencies in from outside, through constructor parameters or setters, so the object does not fetch or create them itself. Production code gets the real object, and tests get a mock. Grimm argues DI would deserve the singleton’s place in a new edition of the GoF book. Here is the logger example rewritten with DI:

class ILogger {
public:
    virtual ~ILogger() = default;
    virtual void write(const std::string& msg) = 0;
};

class OrderService {
public:
    explicit OrderService(ILogger& log) : log_(log) {}
    void place() { log_.write("order placed"); }
private:
    ILogger& log_;
};
// In a unit test: OrderService svc(silentMockLogger);

The dependency is now visible in the constructor, and the test writes no files. The C++ standard library uses the same idea through template parameters: std::vector<T, Allocator> takes its allocator from the caller.

The Monostate pattern lets you create as many instances as you like, but all of them share the same static state. Callers do not see that the state is shared. Python developers know it as the Borg idiom. A Service Locator is a single global registry that hands out dependencies. It is still a singleton, but one central registry is easier to manage than dozens of scattered ones. It is a step toward DI, not a full replacement.

Other Meanings: Singleton Births, Bridge Hands and Single Malt Scotch

Outside software, the word has several common meanings:

  • Medicine: a singleton birth is the birth of one baby from one pregnancy, as opposed to twins or multiples. The clinical definition counts a single birth after at least 20 weeks of pregnancy.
  • Bridge: a singleton is the only card of a suit in a hand.
  • British English: an unmarried person.

Searches for “singleton” also turn up whisky terms such as “single malt scotch” and “12.” These have nothing to do with the design pattern. In single malt whisky, “single” means the whisky was distilled from malted barley at one distillery. It does not refer to a single bottle or a single instance. Rating any whisky is outside the scope of this guide.

Frequently Asked Questions

What does singleton mean?

It means a person or thing that occurs alone. In math, it is a one-element set. In programming, it is a class that allows exactly one instance and provides a global access point to it.

What is a singleton birth?

It is the birth of one child from one pregnancy, as opposed to twins or multiples. The medical definition requires a pregnancy of at least 20 weeks.

How do you implement a thread-safe singleton?

In Java, use a single-element enum or the holder idiom. If you use double-checked locking, the field must be volatile. In C++11 and later, use a Meyers singleton with a local static, delete copy and assignment, and add locks for member access.

Why avoid singletons?

They hide dependencies, carry state from one test to the next, couple callers to a concrete class, and lock in the assumption that there will only ever be one instance. Undoing that assumption later can mean a large refactoring.

What are alternatives to the Singleton design pattern?

Dependency injection is the main one. Monostate and Service Locator are further options, but both still rely on shared global state.

See also

  1. Facade Pattern: Simplifying Complex Subsystems
  2. The Flyweight Pattern: Sharing Objects to Save Memory
  3. Code Smells: Common Examples and How to Refactor Them
  4. Dead Code: How to Find and Safely Remove Unused Code

$ ls tools/

Xref-Speller Refactoring

Direct implementation of several refactorings is performed by others by using its source browsing capabilities. Refactoring, according to Martin Fowler, is a disciplined technique used to restructure codes.

XREF Program

In the current era, the word program does not only anchor its references to party organizations and business meetings, or even events.

Source Browsing

You might think that Xref-Speller illustrated various traces of change when it comes to web-surfing of hypertext files on the Internet.

Programs

The cross-reference file is generated after full pre-processing and parsing of sources (supporting both K&R and ANSI styles).