Double Checked Locking in Singleton
Object-Oriented Design practice on Codemia
Turn requirements into classes, and defend the design, on the problems that come up in OOD rounds.
Introduction
Double-checked locking is a pattern for lazily creating a singleton without paying synchronization cost on every read. It is widely discussed because the idea is simple, but the implementation is only safe when it respects the memory model. In modern Java, that means using volatile.
What the Pattern Tries to Achieve
A normal synchronized singleton is easy to understand:
This is correct, but every call acquires the class monitor. Double-checked locking tries to avoid that overhead after initialization by checking once before locking and again inside the synchronized block.
The outer check avoids locking once the singleton already exists. The inner check ensures only one thread performs construction if several threads race into the first branch.
Why volatile Matters
Without volatile, the code may publish a reference to an object before construction is fully visible to other threads. That sounds abstract, but the effect is real: another thread can observe a non-null reference to a partially initialized object.
The broken version looks almost identical:
The code may pass tests for a long time because concurrency bugs are timing-sensitive. That does not make it safe. The volatile modifier is what gives the publication and visibility guarantees the pattern needs.
When Double-Checked Locking Is Reasonable
Use this pattern only if two conditions are true:
- lazy initialization actually matters
- singleton access happens often enough that the extra complexity is worth it
In many applications, neither condition holds. A simpler eager singleton is often the better engineering choice.
This version is thread-safe because class initialization in Java is already synchronized by the runtime.
Better Alternatives in Java
If you want lazy initialization without the mental overhead of DCL, the holder idiom is usually cleaner.
This relies on class loading semantics and avoids explicit synchronization in the accessor.
For truly global singletons, an enum can be even simpler:
The enum approach is concise and also handles serialization concerns more safely than many hand-written singleton implementations.
Performance and Design Tradeoffs
Developers sometimes choose double-checked locking because it feels like a micro-optimization they "should" apply. In practice, that is rarely the right starting point. Modern JVMs handle uncontended synchronization well, and a singleton accessor is seldom the true bottleneck in a business application.
The bigger risk is design quality. A concurrency-safe singleton can still be poor architecture if it becomes a hidden global store for mutable state. If your singleton contains caches, configuration, or clients that make testing difficult, dependency injection may be a better model than a global accessor.
Common Pitfalls
- Implementing double-checked locking without
volatile. - Using the pattern when eager initialization or the holder idiom would be simpler.
- Assuming the code is safe because it "worked fine" in local tests.
- Hiding mutable global state behind a singleton and making tests harder.
- Optimizing singleton access before measuring whether it matters.
Summary
- Double-checked locking is safe in modern Java only when the instance field is
volatile. - The pattern reduces locking after initialization, but adds complexity.
- Eager initialization, holder idiom, or enum singletons are often clearer choices.
- Correct publication matters more than clever-looking concurrency code.
- Choose a singleton pattern based on measured need, not habit.
Related reading
- DTO and DAO concepts and MVC
- Enterprise Library Unity vs Other IoC Containers
- Enum Inheritance
- Examples of GoF Design Patterns in Java's core libraries
- DownloadStringAsync wait for request completion
- Dynamic periodic tasks - alternatives to Celery beat
- Explicit casting from super-class to sub-class
- Extending an enum via inheritance

OOD Fundamentals
Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Object-Oriented Design practice on Codemia
Turn requirements into classes, and defend the design, on the problems that come up in OOD rounds.