October DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsWindows FixRecommendedWindows errors stealing your time? Find the fix fastScan stability, cleanup and performance issues.Fix NowOctober DealsAmazon USDeal season is back - check today's better picksAmazon US: current deals, useful picks and tech finds.See Picks×
Skip to content
World desk4 min

Java Didn’t Kill Double-Checked Locking: Why the Non-Volatile Version Is Broken

The classic non-volatile double-checked singleton is broken. Java’s volatile-corrected form has a defined happens-before guarantee, while synchronized still serializes initialization.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

No: Java has not universally eliminated double-checked locking. The classic version that publishes a singleton through an ordinary, non-volatile shared field is broken. The commonly shown corrected version uses a volatile field and has a different memory-model justification. The distinction is visible in the code—and in the Java Language Specification’s happens-before rule.

What double-checked locking is trying to do

Double-checked locking aims to initialize a shared object only when first needed, while avoiding a monitor on calls made after initialization. The outer check handles the already-initialized case; the synchronized block protects the initialization path.

As an Amazon Associate I earn from qualifying purchases.

The title’s claim that Java “killed” the pattern is too broad. The Java Memory Model reference describes double-checked locking as broken without explicit memory barriers or assumptions about the processor and compiler. That warning applies to the classic ordinary-reference version, not automatically to the volatile-corrected form. The University of Maryland’s Java Memory Model page explains the historical issue.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Why the old, non-volatile version is broken

In the broken form, the shared field is an ordinary reference. A thread can see a non-null reference without the memory-ordering guarantee needed to ensure that it also sees the object’s constructor writes. The fact that construction appears as one statement in source code does not establish the required publication guarantee under the Java Memory Model.

The JSR-133 reference describes the pattern as broken without explicit memory barriers or assumptions about the processor and compiler. The key issue is not that every execution must fail; it is that the ordinary-reference version does not establish the guarantees the code relies on. The reference and its linked historical material discuss that limitation.

Why the corrected version uses both volatile and synchronized

A conventional corrected form declares the shared field volatile and keeps the second check inside the synchronized block:

final class Service {
    private static volatile Service instance;

    static Service getInstance() {
        Service result = instance;       // first read
        if (result == null) {
            synchronized (Service.class) {
                result = instance;       // second read
                if (result == null) {
                    result = new Service();
                    instance = result;   // volatile publication
                }
            }
        }
        return result;
    }
}

The two synchronization mechanisms have separate roles:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • The volatile field provides memory consistency. The Java Language Specification, Java SE 26, says: “A write to a volatile field happens-before every subsequent read of that field.” A thread that subsequently reads the published reference therefore participates in the specified ordering relationship. See JLS Chapter 17, §17.4.5.
  • The monitor serializes initialization attempts. Only one thread at a time can execute the guarded initialization block for Service.class. The JDK concurrency documentation says volatile reads and writes have memory-consistency effects similar to monitor entry and exit, but “do not entail mutual exclusion locking.” See the Java SE 26 concurrency package documentation.

The second null check matters because another thread may initialize the instance after this thread’s first check but before it acquires the monitor. Once inside, the thread must check again before constructing another object.

These are Java memory-model guarantees, not a claim that volatile makes construction “atomic” or performs a hardware cache flush. The JLS defines the allowed ordering and visibility behavior; implementations may optimize so long as executions remain predictable under those rules. The specification describes those rules.

Why volatile is needed for this idiom

Without volatile, the fast-path read outside the synchronized block is not protected by that monitor. The volatile declaration supplies a defined happens-before edge between publication through the field and a subsequent read of that same field. The synchronized block alone cannot give an unsynchronized fast-path reader the same monitor-based guarantee.

Conversely, volatile alone does not serialize competing first-time initializers. The monitor prevents two threads that both observe null from simultaneously completing the guarded initialization. The idiom depends on both properties, not on volatile serving as a substitute for every form of synchronization.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Safe publication does not make later changes thread-safe

Correctly publishing the reference and its construction-time state is separate from making future operations on the object safe under concurrent use. A volatile reference does not automatically protect mutable fields or compound operations inside the object.

The JLS gives special guarantees to correctly initialized final fields when construction completes before another thread sees the reference. It does not extend that same guarantee to ordinary non-final fields merely because the reference was observed. Its example permits a racy reader to see a final field’s initialized value while seeing the default value of a non-final field. See JLS §17.5 on final-field semantics. If a singleton’s state can change after construction, its methods and mutable data still need an appropriate concurrency design.

When to choose another initialization approach

Double-checked locking is one option, not a universal default. Choose based on whether initialization must be lazy, whether construction is parameterized or can fail, and whether the object’s later state is mutable. The JDK documents higher-level concurrency facilities and their memory-consistency guarantees, but the sources cited here do not establish a universal performance winner among singleton approaches. Avoid choosing on the basis of an assumed speed advantage without measurements for the actual application.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
PC Slower Than It Used to Be?Free scan - under a minute
Outdated Drivers Are Slowing You DownFree scan - exact matches

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.