How to solve the Double-Checked Locking is Broken Declaration in Java?
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.
Introduction
The phrase "double-checked locking is broken" refers to the old unsafe form of lazy singleton initialization in Java. The short modern answer is: double-checked locking is safe in Java if the instance field is declared volatile, but many codebases should still prefer simpler patterns such as the initialization-on-demand holder idiom or an enum singleton.
Why the Old Version Was Broken
The classic broken pattern looked like this:
The problem is not the two if checks themselves. The problem is publication without the right memory-visibility guarantees. Without volatile, another thread can observe a reference to an incompletely constructed object due to reordering and visibility effects.
The Safe Modern Version
In modern Java, the standard double-checked locking fix is to make the field volatile.
volatile ensures the write to instance is published safely and that readers do not observe a partially initialized object.
What volatile Actually Fixes
The key guarantee is not merely "always read from memory". The important part is safe publication and the required happens-before relationship around writes and reads of the singleton reference.
That makes the constructed object visible only after construction is complete from the perspective required by the Java memory model.
When to Prefer the Holder Idiom
Even though volatile makes double-checked locking correct, the holder pattern is often simpler and clearer.
This gives you lazy initialization without explicit synchronization code in getInstance.
Enum Singleton Is Even Simpler
If you truly need one singleton instance and no lazy holder complexity, an enum is often the cleanest option.
Usage:
This is concise, thread-safe, and robust against several serialization pitfalls that affect ordinary singleton classes.
Which Approach Should You Choose
A practical rule set:
- use
volatiledouble-checked locking only if you specifically need that shape - use the holder idiom for clear lazy initialization
- use an enum when you want the simplest singleton form
Many teams reach for double-checked locking by habit when one of the other patterns would be easier to read and maintain.
Performance Considerations
Double-checked locking exists to avoid paying synchronization cost on every call after initialization. In modern JVMs, that overhead is often far less important than people assume, especially compared with correctness and clarity. Do not introduce concurrency complexity based only on old folklore.
Measure if singleton-access performance is truly a hotspot.
Common Pitfalls
The most common mistake is using double-checked locking without volatile and assuming the synchronized block alone is enough. Another is treating "double-checked locking is broken" as a timeless statement without understanding that modern Java memory rules make the volatile form safe. Teams also sometimes use a complicated singleton pattern when a holder class or enum would be clearer. Finally, over-optimizing singleton creation paths without evidence often adds complexity for no real gain.
Summary
- The old form of double-checked locking in Java was broken because of unsafe publication.
- The modern safe form requires the singleton field to be
volatile. - The holder idiom is often a cleaner lazy-initialization alternative.
- Enum singletons are simple and robust when they fit the design.
- Prefer the simplest correct pattern unless profiling justifies the more complex one.
Related reading
- How to specify a callback method for IAsyncOperation
- How to specify a part of code to run in a particular thread in a multithreaded environment in python?
- How to start an async method without await its completion?
- How to start two threads at exactly the same time
- How to solve the “failed to lazily initialize a collection of role” Hibernate exception
- How to solve Timeout FeignClient
- How to stop a looping thread in Python?
- How to stop a thread created by implementing runnable interface?

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.
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.