0% completed
Singleton Pattern
On This Page
Structure of Singleton Pattern
Implementation of Singleton Pattern
Pseudocode
Initialization and Thread Safety
The naive lazy version is not thread safe
Two lazy versions that are safe
Which one to pick
Where You Have Already Used It
When Not to Use It
Pros and Cons
Often Confused With
In Modern Languages
Summary
The Singleton Pattern restricts a class to one instance and gives every caller the same way to reach it.
Some things should exist once per process. A configuration object read from a file at start-up. A connection pool. A metrics registry that everything reports into. If every part of the application builds its own, you get twenty copies of the configuration, twenty reads of the same file, and twenty registries that nobody can add up.
Consider a ConfigStore that holds settings loaded from disk: the region to call, how many times to retry, how long to wait. Billing needs it. The nightly report job needs it. The email service needs it. If each one constructs its own store, then a setting changed in one place is invisible in the others, and the file is read three times for no reason.
The obvious fix is a global variable. That works until you need to test the code, at which point every test shares it and the results depend on which test ran first.
The Singleton pattern solves this by making the class itself responsible for how many of it exist. The constructor is private, so no caller can build one. A single public method hands back the one instance, creating it the first time if it does not exist yet.
That last part is what separates a Singleton from a global variable. With a global, some piece of code assigns it and everyone hopes that happened first. With a Singleton, the class owns its own lifecycle and there is no order to get wrong.
Structure of Singleton Pattern
Following is the class diagram of the Singleton Pattern, using the ConfigStore from above.
- ConfigStore
INSTANCE: a private static field holding the single object. It is static because it belongs to the class, not to any one caller.ConfigStore(): the constructor, marked private. This is the line that enforces the pattern. Delete the wordprivateand the whole guarantee is gone.getInstance(): the only way in. It is static, because you have to be able to call it without already holding an instance, which is the problem it exists to solve.get()andset(): ordinary methods on the shared object.
- BillingService is any caller. It never constructs a
ConfigStore, it asks for one, and it gets the same object every other caller gets.
Implementation of Singleton Pattern
This section implements ConfigStore in Java, Python, JavaScript, and C++. The shape is the same in all four, but the mechanism differs, because the languages disagree about what a private constructor even is.
Pseudocode
CLASS ConfigStore // One instance, created when the class is loaded PRIVATE STATIC FINAL INSTANCE = NEW ConfigStore() PRIVATE values : Map // Private, so no caller can build a second one PRIVATE CONSTRUCTOR ConfigStore() values = read settings from disk PUBLIC STATIC FUNCTION getInstance() RETURNS ConfigStore RETURN INSTANCE PUBLIC FUNCTION get(key) RETURNS String RETURN values[key] PUBLIC FUNCTION set(key, value) values[key] = value END CLASS MAIN billing = ConfigStore.getInstance() reports = ConfigStore.getInstance() PRINT billing.get("region") // us-east-1 reports.set("region", "eu-west-1") PRINT billing.get("region") // eu-west-1, the same object END MAIN
The last three lines are the point of the whole pattern. reports changes a setting and billing sees it, without the two ever knowing about each other, because there is only one store.
Initialization and Thread Safety
The Java implementation above builds the instance eagerly: the static final field is assigned when the class is loaded, before anyone calls getInstance(). That is the simplest correct Singleton in Java, and it is thread safe for free, because the class loader guarantees a class is initialized exactly once no matter how many threads reach it.
It has one cost. The object is built even in a run that never asks for it. When the constructor is expensive, for example one that opens a file or a socket, you may prefer to build it on first use instead. That is lazy initialization.
The naive lazy version is not thread safe
// Do not use this version. public static ConfigStore getInstance() { if (INSTANCE == null) { INSTANCE = new ConfigStore(); } return INSTANCE; }
Two threads can both evaluate INSTANCE == null as true before either assigns, and you end up with two stores, which means a setting written to one is invisible in the other. On a single thread this code looks correct, which is what makes the bug easy to ship. The same hole exists in the Python version above: two threads can both pass the if cls._instance is None check.
Two lazy versions that are safe
The holder idiom is the usual choice in Java. The nested class is not loaded until getInstance() first mentions it, so initialization is lazy, and the class loader still guarantees it happens once.
class ConfigStore { private ConfigStore() { } private static class Holder { private static final ConfigStore INSTANCE = new ConfigStore(); } public static ConfigStore getInstance() { return Holder.INSTANCE; } }
Double-checked locking is the other. It checks without the lock first, so the common case stays cheap, then checks again while holding it. The volatile matters: without it another thread can see a reference to an object whose constructor has not finished.
class ConfigStore { private static volatile ConfigStore instance; private ConfigStore() { } public static ConfigStore getInstance() { if (instance == null) { synchronized (ConfigStore.class) { if (instance == null) { instance = new ConfigStore(); } } } return instance; } }
In Python the same shape uses a lock:
import threading class ConfigStore: _instance = None _lock = threading.Lock() def __new__(cls): if cls._instance is None: with cls._lock: if cls._instance is None: cls._instance = super().__new__(cls) return cls._instance
The C++ version above is already lazy and already safe: a function-local static is initialized on first call, and the standard guarantees that happens once even when several threads arrive together. JavaScript needs none of this on a single event loop, since two pieces of synchronous code never interleave. Web Workers do not share the object graph, so each worker gets its own instance, which is worth knowing before you rely on a browser singleton for shared state.
Which one to pick
Start eager. It is shorter, it cannot race, and the cost only matters when the constructor is expensive. Move to the holder idiom when you measure a start-up cost worth removing. Reach for double-checked locking when the instance depends on something known only at run time, and remember the volatile.
Where You Have Already Used It
You have almost certainly called into a Singleton today without writing one:
- Loggers.
Logger.getLogger(name)in Java andlogging.getLogger(name)in Python both return a shared object per name, so every part of the application writes into the same stream. - Connection pools. The pool is the single resource, and handing out connections is its job. Building two pools defeats the point of pooling.
- Runtime and environment handles.
Runtime.getRuntime()in Java is a Singleton, as is the browser'swindowobject. - Metrics and feature-flag registries. These only work if there is exactly one place the numbers accumulate or the flags are read from.
The common thread is that the object represents a genuinely single thing: one file on disk, one pool of sockets, one process. That is the test worth applying before you reach for the pattern.
When Not to Use It
This is the most overused pattern in the set, so this section is longer than usual.
- You just want easy access to an object. That is what passing an argument is for. Convenience is not a design reason, and it is why most Singletons in real codebases should not have been Singletons.
- The object holds mutable state your tests will touch. Every test now shares it. You will lose an afternoon to a test that passes alone and fails in the suite.
- Your framework already does this. Any dependency injection container gives you one instance per container without a private constructor, and lets tests swap it out. If you are using Spring, Guice, NestJS, or anything similar, register the class in singleton scope and stop there.
- You have more than one process. A Singleton is one instance per process, not one per system. On four servers you have four. Using it for locking or for generating unique IDs is a correctness bug, not a style preference.
Pros and Cons
| Pros | Cons |
|---|---|
| Controlled Instance Access: exactly one instance exists, with one documented way to reach it. | Global State: encourages global mutable state, with every problem global mutable state has always had. |
| Controlled Creation Time: you choose whether the instance is built eagerly at class load or lazily on first use, trading start-up cost against simplicity. | Testing Challenges: hard to substitute in a test unless you add a reset hook, which then exists in production code where somebody will eventually call it. |
| Shared Resource Management: the natural fit for a connection pool, a cache, or a device handle, where a second copy would be wrong. | Hidden Dependencies: a class that calls getInstance() does not declare that dependency in its constructor, so you cannot see it from the outside. |
| No Repeated Setup Cost: expensive initialization happens once per process rather than once per caller. | Scalability Limits: uniqueness stops at the process boundary, which surprises people who reach for it to coordinate across machines. |
Subclassing, if you plan for it: a singleton can return a subclass chosen at run time, but only when the constructor is protected rather than private. The implementation above uses a private constructor and so cannot be subclassed. | Refactoring Hurdles: turning a Singleton back into an ordinary class means touching every call site, and by then there are many. |
Often Confused With
| Looks like | The actual difference |
|---|---|
| Static utility class | A static class cannot implement an interface or be passed as an argument. A Singleton is still an object, so it can be substituted in a test or behind an interface. That is the main reason to prefer one. |
| Prototype | Opposite intent. Singleton guarantees one instance, while Prototype exists to produce many by copying. |
| Dependency injection singleton scope | Same outcome, better mechanism. The container owns the lifecycle, callers still declare what they depend on, and tests can replace it. |
In Modern Languages
Some languages give you this for free, and writing the classic version is then just extra code:
- Python: a module runs once, so a module-level object is already a Singleton. Everything that imports it gets the same object, and the
__new__gymnastics are usually unnecessary. - Java: a single-element
enumis the shortest thread-safe version, and unlike the field-based versions it survives serialization. - JavaScript and TypeScript: a module that exports an already-constructed object gives you the same guarantee with no ceremony.
- Go: a package-level variable initialized with
sync.Onceis the idiomatic form. - C++: the function-local
staticused above, often called a Meyers Singleton, is both lazy and thread safe with no extra machinery.
Summary
The Singleton pattern guarantees one instance of a class per process and gives every caller one way to reach it. The private constructor is what enforces it, and the static accessor is what makes it usable. Build eagerly unless the constructor is expensive, and if you go lazy, know which mechanism makes it safe in the language you are writing.
Its strengths are real when the object represents something genuinely single: one config file, one pool, one registry. Its costs are also real, and they are mostly the costs of global mutable state, paid later by whoever writes the tests.
In an interview, naming the pattern earns very little. What earns marks is the second sentence:
- Say which initialization you would use and why: "eager, because the class loader guarantees it happens once and I get thread safety without writing any."
- Say what it costs: hidden dependencies and awkward tests.
- Say where it stops working: one instance per process, so it is the wrong tool for anything spanning machines.
- If the interviewer is using a framework with a container, say you would use its singleton scope instead. Knowing when not to hand-write the pattern reads as more experience, not less.
Jitendra Sabat
· 4 months ago
This is not thread safe. Can we have complete example with thread safety in mind.
prabrisha
· a year ago
You have only provided examples on eager loading of singleton instances. please provide some examples and explanations/discussion on lazy loading too. Also, you have provided a private constructor. But, in the pros section, you have mentioned the subclass/extendable feature. Please provide relevant example too.
Reading Progress
0%
On This Page
Structure of Singleton Pattern
Implementation of Singleton Pattern
Pseudocode
Initialization and Thread Safety
The naive lazy version is not thread safe
Two lazy versions that are safe
Which one to pick
Where You Have Already Used It
When Not to Use It
Pros and Cons
Often Confused With
In Modern Languages
Summary