Bird
Raised Fist0
Interview Prepoop-design-patternsmediumAmazonGoogleMicrosoftFlipkartSwiggyRazorpayPhonePeCRED

Singleton Pattern - Thread Safety, Double-Checked Locking & Lazy Init

Choose your preparation mode3 modes available
▶
Steps
setup

Define Singleton class with _instance field

The Singleton class is defined with a private static field _instance initialized to null. This field will hold the single instance of the class.

💡 This setup is crucial because _instance is the core of the singleton pattern, storing the unique instance.
Line:class Singleton: _instance = null
💡 The singleton instance is stored as a class-level field, initially empty.
📊
Singleton Pattern - Thread Safety, Double-Checked Locking & Lazy Init - Watch the Algorithm Execute, Step by Step
Watching each step reveals how thread safety and lazy initialization are achieved, which is difficult to grasp by reading code alone.
Step 1/10
·Active fill★Answer cell
Encapsulation of the singleton instance in a private static field
Singleton
−_instance: Singleton|null
Polymorphism: overriding __new__ to control instantiation
Singleton
−_instance: Singleton|null
+__new__()
Lazy initialization check
Singleton
−_instance: Singleton|null
+__new__()
Singleton instance creation and assignment
Singleton
−_instance: Singleton
+__new__()
Consistent instance return
Singleton
−_instance: Singleton
+__new__()
Multiple calls to singleton constructor
Singleton
−_instance: Singleton
+__new__()
Double-checked locking simulation: no new instance created
Singleton
−_instance: Singleton
+__new__()
Singleton instance reuse
Singleton
−_instance: Singleton
+__new__()
Verification of singleton uniqueness
Singleton
−_instance: Singleton
+__new__()
Singleton pattern with thread-safe lazy initialization
Singleton
−_instance: Singleton
+__new__()

Key Takeaways

✓ Singleton instance is created lazily and stored in a private static field.

This insight is hard to see from code alone because the lazy creation and storage happen inside __new__, which is not obvious without tracing.

✓ Multiple threads calling getInstance() concurrently receive the same instance without creating duplicates.

Visualizing the check and return steps clarifies how thread safety is maintained, which is subtle in code.

✓ Overriding __new__ (or using synchronized getInstance) controls instance creation and enforces singleton behavior.

Seeing the method activation and decision branches helps understand how polymorphism and synchronization enforce the pattern.

Practice

(1/5)
1. In designing a parking lot system using OOP, which component is best suited to decide which type of parking spot (e.g., compact, large, handicapped) should be allocated to an incoming vehicle?
easy
A. The ParkingLot class, as it manages all spots and vehicles
B. The ParkingSpot class, since it represents the spot's characteristics
C. The Vehicle class, because it knows its own size and type
D. A Factory or Strategy pattern component that encapsulates the allocation logic

Solution

  1. Step 1: Understand responsibilities

    The Vehicle class only knows about itself, not allocation rules. The ParkingSpot class represents a spot but doesn't decide allocation. The ParkingLot manages overall state but delegating allocation logic to a dedicated component improves modularity.
  2. Step 2: Recognize design pattern role

    The Factory or Strategy pattern encapsulates allocation logic, allowing easy extension and modification without changing core classes.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Allocation logic centralized -> easier to maintain and extend [OK]
Hint: Allocation logic belongs in a dedicated pattern component, not core entities [OK]
Common Mistakes:
  • Assigning allocation responsibility to Vehicle or ParkingSpot classes
  • Putting all logic inside ParkingLot class leading to tight coupling
2. Trace the sequence of events when a client tries to update a private field via a setter method in an encapsulated class.
easy
A. The client directly modifies the private field without any method call
B. The getter method is called first to check the current value before updating
C. The setter method validates the input, updates the private field, then returns control to the client
D. The private field is copied to a public variable which the client modifies

Solution

  1. Step 1: Identify encapsulation flow

    Private fields cannot be accessed directly; setters provide controlled access.
  2. Step 2: Follow setter method process

    Setter receives input, validates it, updates the private field, then returns control.
  3. Step 3: Analyze incorrect options

    The client directly modifies the private field without any method call violates data hiding. The getter method is called first to check the current value before updating misuses getter before setter. The private field is copied to a public variable which the client modifies breaks encapsulation by exposing private data.
  4. Final Answer:

    Option C -> Option C
  5. Quick Check:

    Setters control updates with validation, preserving encapsulation.
Hint: Setters validate and update private data, not direct access [OK]
Common Mistakes:
  • Assuming direct field access through setters
  • Confusing getter and setter roles
  • Thinking private data is copied out for modification
3. Which of the following statements about composition and inheritance is INCORRECT?
medium
A. Composition leads to tighter coupling between classes than inheritance.
B. Inheritance models 'is-a' relationships, while composition models 'has-a' relationships.
C. Favoring composition improves flexibility and maintainability of code.
D. Inheritance can cause fragile base class problems when base classes change.

Solution

  1. Step 1: Analyze each statement

    Options A, C, and D are correct statements. Composition leads to tighter coupling between classes than inheritance. is incorrect because composition reduces coupling by separating concerns, whereas inheritance creates tighter coupling due to dependency on base classes.
  2. Final Answer:

    Option A -> Option A
  3. Quick Check:

    Composition reduces coupling; inheritance increases it.
Hint: Composition reduces coupling; inheritance increases coupling.
Common Mistakes:
  • Confusing which relationship leads to tighter coupling
  • Assuming composition increases coupling
4. What is the time complexity of computing the cost() method when stacking k decorators on a core object using the Decorator Pattern with dynamic behavior injection?
medium
A. O(1) because each decorator adds a fixed cost
B. O(k) because each decorator delegates the call to the next one
C. O(k^2) because each decorator calls all previous decorators recursively
D. O(log k) because decorators form a balanced tree structure

Solution

  1. Step 1: Identify call chain length

    Each decorator's cost() calls the wrapped object's cost(), forming a chain of length k.
  2. Step 2: Calculate total calls

    Cost computation requires traversing all k decorators once, so time complexity is O(k).
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Each decorator adds constant work, total linear in k [OK]
Hint: Decorator calls chain length equals number of decorators [OK]
Common Mistakes:
  • Assuming O(1) because cost is a simple addition
  • Mistaking recursive calls as quadratic
5. Suppose you want to implement a prototype pattern for an object that contains references to other objects which themselves may reference back to the original object (cyclic references). Which approach correctly handles deep copying in this scenario?
hard
A. Use a deep copy implementation with memoization to track already copied objects and avoid infinite recursion
B. Use a naive recursive deep copy without memoization, which will eventually copy all objects
C. Use shallow copy to avoid recursion issues, accepting shared nested references
D. Serialize the object to JSON and deserialize it, which naturally handles cyclic references

Solution

  1. Step 1: Understand cyclic references problem

    Naive recursion without tracking copied objects causes infinite recursion on cycles.
  2. Step 2: Evaluate solutions

    Memoization tracks already copied objects, preventing infinite loops and ensuring correct deep copy. Shallow copy shares references, breaking independence. JSON serialization cannot handle cycles and will fail.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Memoization prevents infinite recursion in cyclic graphs [OK]
Hint: Memoization is essential for deep copying cyclic object graphs [OK]
Common Mistakes:
  • Ignoring cycles causes infinite recursion or stack overflow
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard