Lazy Initialization Race

Creating a heavy resource exactly once... or maybe twice?

The idea

Creating a Database Connection Pool is slow (e.g., 200ms). You don't want to create it when the app boots up, because it might not be used. Instead, you Lazy Initialize it: the first time someone asks for the DB, you check if it exists. If not, you create it. But what happens if two threads ask for the DB at the exact same millisecond? They both see it doesn't exist, and they both create a new connection pool.

Step 1: The DB variable is null. Two web requests arrive simultaneously.

How it works (Double-Checked Locking)

The naive fix is to put a lock around the entire get_db() function. But this destroys performance: every future request has to acquire a lock just to read the variable! The standard pattern is Double-Checked Locking: check without a lock, if null, grab the lock, and check again just in case another thread created it while you were waiting.

# The classic Double-Checked Locking pattern (Java/C#)

private volatile Database db = null;

public Database getDb() {
    if (db == null) {                 // 1st Check (Fast, no lock)
        synchronized(this) {          // Acquire Lock
            if (db == null) {         // 2nd Check (Inside lock)
                db = new Database();  // Safe Init
            }
        }
    }
    return db;
}

Cost

The cost of Double-Checked Locking is language complexity. In older versions of Java, memory reordering by the CPU could cause the first check to see a half-initialized object! You must always mark the variable as volatile to prevent CPU cache/instruction reordering bugs.

Watch out for