Lazy Initialization

⭐ Interview Importance: MEDIUM
⏱️ Revision Time: 5 min

TL;DR

  • Lazy Initialization is a performance optimization technique where you delay the creation of an object or the calculation of a value until the exact moment it is first needed.
  • It saves memory and speeds up application startup times.
  • If the initialization never actually happens (because the user never clicked that specific feature), you save 100% of the overhead.

Concept

Imagine an application with a HeavyDataAnalyzer class that loads 500MB of machine learning models into memory when instantiated.
If you instantiate this class immediately when the application starts (Eager Initialization), the startup time slows down by 10 seconds, and 500MB of RAM is consumed.
What if the user just wants to check their profile settings and logs out? The ML models were loaded for nothing!

With Lazy Initialization, the variable starts as null. Only when a method specifically requests the analyzer do you check if it’s null, instantiate it, and return it.

Examples

public class AnalyticsService {
    
    // Starts as null. No memory used.
    private HeavyDataAnalyzer analyzer = null;

    // The classic Lazy Initialization pattern (Non-Thread-Safe)
    public HeavyDataAnalyzer getAnalyzer() {
        if (analyzer == null) {
            // Expensive loading process only happens the FIRST time this is called!
            System.out.println("Loading 500MB models...");
            analyzer = new HeavyDataAnalyzer();
        }
        return analyzer;
    }
}

// Spring Boot Example
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

@Lazy
@Component
public class SpringHeavyComponent {
    // Spring will normally instantiate all @Components at startup.
    // @Lazy tells Spring to NOT instantiate this until another bean actually 
    // injects it or requests it. Speeds up Spring startup times!
}

Interview Questions

Q: Why is the standard lazy initialization pattern dangerous in Multithreading?
A: If you have if (analyzer == null) { analyzer = new Analyzer(); }, and Thread A and Thread B call the method at the exact same millisecond, they both evaluate the if condition to true. They will both execute the expensive initialization logic, creating two separate objects and overwriting each other, wasting resources and potentially causing data corruption.

Q: How do you make Lazy Initialization Thread-Safe?
A: 1. Synchronized Method: public synchronized getAnalyzer(). Easy, but adds a performance lock penalty to every single read, even after initialization.
2. Double-Checked Locking: You check for null, enter a synchronized block, and check for null again. You MUST mark the variable as volatile for this to work correctly due to the Java Memory Model.
3. Initialization-on-Demand Holder Idiom: (The best approach). You create a private static inner class that holds the instance. The JVM guarantees that classes are only loaded and initialized once, making it 100% thread-safe without any locking overhead.