Printing is unavailable

This course is licensed for personal online viewing only.

Public preview • CL-P000000-C41-L1542-E8A129A5

Home Dashboard
Chapter 434 · Module 2 — Creational Design Patterns

Singleton Pattern

4,941
words
28
min read
3
tools

1. Learning Outcomes#

इस chapter को पूरा करने के बाद आप:

  • Singleton Pattern का मुख्य intent समझ पाएँगे।
  • समझ पाएँगे कि किसी class की केवल एक controlled instance क्यों चाहिए हो सकती है।
  • private constructor और controlled access का purpose समझ पाएँगे।
  • Eager और Lazy Singleton implement कर पाएँगे।
  • समझ पाएँगे कि simple lazy Singleton multithreaded environment में क्यों fail हो सकता है।
  • synchronized access, Double-Checked Locking और volatile का role समझ पाएँगे।
  • Initialization-on-Demand Holder idiom और Enum Singleton का उपयोग समझ पाएँगे।
  • अलग-अलग Singleton approaches के trade-offs compare कर पाएँगे।
  • testing, global state और tight coupling से जुड़ी design problems पहचान पाएँगे।
  • serialization, reflection और multiple class loaders से जुड़े important pitfalls समझ पाएँगे।
  • यह decide कर पाएँगे कि Singleton कहाँ useful है और कहाँ avoid करना चाहिए।

2. Singleton की जरूरत कहाँ से आती है?#

मान लीजिए आपकी application में एक ऐसा component है जो application-level configuration manage करता है।

आप चाहते हैं कि पूरी application उसी एक configuration object का उपयोग करे।

अगर हर class अपनी अलग configuration object बनाए, तो अलग-अलग objects में अलग state आ सकती है।

उदाहरण के लिए:

  • एक object production configuration पढ़ रहा है।
  • दूसरा object पुरानी configuration रख रहा है।
  • तीसरा object अपने अलग cached values रख रहा है।

इससे application का behavior inconsistent हो सकता है।

यहाँ हमें एक ऐसी व्यवस्था चाहिए जिसमें object creation uncontrolled न हो।

यही problem Singleton Pattern address करता है।

Key Idea

Singleton Pattern का मुख्य उद्देश्य केवल "new को रोकना" नहीं है। इसका उद्देश्य instance creation को control करना और उस controlled instance तक access देना है।

3. Singleton Pattern क्या है?#

Singleton एक Creational Design Pattern है।

इसका intent है:

किसी class के instance creation को control करना ताकि सामान्य application context में उसी class की एक shared instance उपयोग की जा सके, और उस instance तक controlled access उपलब्ध हो।

शुरुआत में इसे ऐसे याद रखें:

एक class → controlled creation → shared instance → controlled access

लेकिन एक important technical detail बाद में याद रखनी है:

Java में Singleton सामान्यतः per class loader होता है।

इसलिए "पूरे JVM में हमेशा केवल एक object" कहना हर situation में technically सही नहीं है।

4. Basic Mental Model#

एक office building में एक central reception desk imagine कीजिए।

हर visitor अपने लिए नया reception desk नहीं बनाता।

सभी लोग एक controlled point पर जाते हैं।

Singleton का mental model कुछ ऐसा है:

Visual Diagram80%

Rendering diagram…

यहाँ clients direct constructor call नहीं करते।

वे controlled access method से instance लेते हैं।

5. Singleton के तीन मुख्य हिस्से#

एक basic Singleton में सामान्यतः तीन concepts होते हैं:

  1. constructor बाहर से accessible नहीं होता
  2. class अपनी instance को स्वयं hold करती है
  3. एक controlled method उस instance को return करता है

इन्हें एक-एक करके समझते हैं।

6. Private Constructor क्यों चाहिए?#

Normal Java class में हम ऐसा कर सकते हैं:

JAVA
Service service = new Service();

लेकिन अगर कोई भी code new करके object बना सकता है, तो Singleton एक instance कैसे control करेगा?

इसीलिए constructor को सामान्यतः private बनाया जाता है।

JAVA
public class AppConfig {

    private AppConfig() {
    }
}

अब outside code यह नहीं कर सकता:

JAVA
AppConfig config = new AppConfig();

क्योंकि constructor class के बाहर accessible नहीं है।

Remember

private constructor अपने आप Singleton नहीं बनाता। वह केवल outside code द्वारा normal construction को रोकता है। Instance create और provide करने की responsibility class को अभी भी implement करनी होती है।

7. Controlled Instance Access#

अब class को अपनी instance store करनी होगी।

इसके लिए सामान्यतः static field use किया जाता है।

फिर एक static method instance return करता है।

Conceptual structure:

JAVA
public class AppConfig {

    private static AppConfig instance;

    private AppConfig() {
    }

    public static AppConfig getInstance() {
        return instance;
    }
}

लेकिन यह code अभी incomplete है क्योंकि instance create ही नहीं हुई।

Instance कब create करनी है?

यहीं से अलग-अलग Singleton implementations शुरू होती हैं।

8. Eager Singleton Initialization#

Eager Initialization में instance class initialization के समय ही create कर दी जाती है।

JAVA
public class AppConfig {

    private static final AppConfig INSTANCE = new AppConfig();

    private AppConfig() {
    }

    public static AppConfig getInstance() {
        return INSTANCE;
    }
}

यहाँ:

JAVA
private static final AppConfig INSTANCE = new AppConfig();

class की single instance create करता है।

और:

JAVA
public static AppConfig getInstance() {
    return INSTANCE;
}

हर caller को वही reference return करता है।

एक छोटा complete example देखते हैं।

JAVA
class AppConfig {

    private static final AppConfig INSTANCE = new AppConfig();

    private AppConfig() {
    }

    public static AppConfig getInstance() {
        return INSTANCE;
    }
}

public class Main {

    public static void main(String[] args) {
        AppConfig first = AppConfig.getInstance();
        AppConfig second = AppConfig.getInstance();

        System.out.println(first == second);
    }
}

Expected Output#

TEXT
true

Output true क्यों आया?

क्योंकि दोनों variables को दो अलग objects नहीं मिले।

दोनों references उसी INSTANCE object को point कर रहे हैं।

Eager Initialization के फायदे#

  • implementation बहुत simple है
  • Java class initialization के कारण instance creation thread-safe होती है
  • explicit synchronization की जरूरत नहीं पड़ती
  • implementation समझना और maintain करना आसान है

Eager Initialization की limitation#

Object class initialize होते ही create हो जाता है।

अगर object expensive है और application कभी उसे use ही नहीं करती, तो unnecessary resource usage हो सकती है।

उदाहरण:

  • expensive cache initialization
  • large configuration loading
  • costly resource preparation

इस situation में lazy initialization useful हो सकती है।

9. Lazy Singleton Initialization#

Lazy Initialization का मतलब है:

Object पहले से create मत करो।

जब पहली बार जरूरत पड़े, तभी create करो।

Basic implementation:

JAVA
public class LazyConfig {

    private static LazyConfig instance;

    private LazyConfig() {
    }

    public static LazyConfig getInstance() {
        if (instance == null) {
            instance = new LazyConfig();
        }

        return instance;
    }
}

पहली call पर:

JAVA
instance == null

true होगा।

इसलिए object create होगा।

बाद की calls में instance पहले से मौजूद होगी।

इसलिए वही object return होगा।

Flow:

Visual Diagram80%

Rendering diagram…

Single-threaded environment में यह logic straightforward लगता है।

लेकिन multithreaded application में एक serious problem है।

10. Simple Lazy Singleton Multithreading में क्यों टूट सकता है?#

मान लीजिए दो threads हैं:

  • Thread A
  • Thread B

और शुरुआत में:

instance == null

Thread A यह check करता है:

instance == null

उसे true मिलता है।

लेकिन object create करने से पहले CPU Thread B को execute कर देता है।

Thread B भी check करता है:

instance == null

उसे भी true मिलता है।

अब दोनों threads object create कर सकते हैं।

Conceptually:

Step Thread A Thread B
1 instance == null → true
2 paused instance == null → true
3 creates object A
4 creates object B

अब Singleton का "single controlled instance" requirement break हो गया।

Common Mistake

केवल if (instance == null) लिख देना thread safety नहीं देता। Check और object creation अलग operations हैं, इसलिए race condition हो सकती है।

11. Thread-Safe Singleton with synchronized#

इस problem का simple solution है getInstance() को synchronized बनाना।

JAVA
public class SafeConfig {

    private static SafeConfig instance;

    private SafeConfig() {
    }

    public static synchronized SafeConfig getInstance() {
        if (instance == null) {
            instance = new SafeConfig();
        }

        return instance;
    }
}

अब एक समय में केवल एक thread synchronized method execute कर सकती है।

अगर Thread A method के अंदर है, तो Thread B को wait करना पड़ेगा।

Thread A object create करेगी।

बाद में Thread B अंदर आएगी और पाएगी:

JAVA
instance != null

इसलिए दूसरा object create नहीं होगा।

इसका फायदा#

Implementation बहुत easy है।

Thread safety समझना भी आसान है।

इसका trade-off#

Synchronization केवल first creation के समय नहीं होती।

हर getInstance() call synchronized method से गुजरती है।

अधिकतर applications में यह difference critical नहीं होगा, लेकिन high-frequency access में unnecessary synchronization avoid करना desirable हो सकता है।

इसी requirement से Double-Checked Locking approach आती है।

12. Double-Checked Locking#

Goal है:

  • object lazy create हो
  • creation thread-safe हो
  • object create होने के बाद हर call पर synchronization न करनी पड़े

Implementation:

JAVA
public class DatabaseManager {

    private static volatile DatabaseManager instance;

    private DatabaseManager() {
    }

    public static DatabaseManager getInstance() {

        if (instance == null) {

            synchronized (DatabaseManager.class) {

                if (instance == null) {
                    instance = new DatabaseManager();
                }
            }
        }

        return instance;
    }
}

यहाँ दो null checks हैं।

इसीलिए इसे Double-Checked Locking कहा जाता है।

13. पहला null check क्यों है?#

JAVA
if (instance == null)

अगर instance पहले से create हो चुकी है, तो synchronization block enter करने की जरूरत नहीं है।

Method directly existing instance return कर सकती है।

इससे normal later calls cheap रहती हैं।

14. synchronized block क्यों है?#

अगर instance अभी null है, तो threads creation area तक पहुँच सकती हैं।

इसलिए creation logic को:

JAVA
synchronized (DatabaseManager.class)

के अंदर रखा जाता है।

इससे एक समय में एक thread critical section execute करती है।

15. दूसरा null check क्यों चाहिए?#

यह सबसे important हिस्सा है।

कल्पना कीजिए:

  1. Thread A first null check pass करती है।
  2. Thread B भी first null check pass कर लेती है।
  3. Thread A synchronized block में जाती है।
  4. Thread A instance create कर देती है।
  5. Thread A block छोड़ देती है।
  6. Thread B अब synchronized block में enter करती है।

अगर अंदर second check न हो, तो Thread B भी नया object create कर सकती है।

इसीलिए synchronized block के अंदर फिर से:

JAVA
if (instance == null)

check किया जाता है।

Visual Diagram80%

Rendering diagram…

16. volatile क्यों जरूरी है?#

Double-Checked Locking implementation में field को इस तरह declare किया जाता है:

JAVA
private static volatile DatabaseManager instance;

यहाँ volatile decoration नहीं है।

यह correctness का important हिस्सा है।

Object creation को simplified form में ऐसा समझ सकते हैं:

  1. memory allocate हुई
  2. object initialize हुआ
  3. reference instance में assign हुआ

Compiler और CPU optimizations के कारण memory operations का ordering हमारे source-code intuition जैसा हमेशा नहीं होना चाहिए।

गलत publication scenario में किसी दूसरे thread को reference दिखाई दे सकता है जबकि object की initialization safely visible न हुई हो।

volatile दो important guarantees में मदद करता है:

  • visibility — एक thread द्वारा लिखी value दूसरे threads को properly visible हो
  • ordering — reference publication के आसपास unsafe reordering न हो
Important

Modern Java में standard Double-Checked Locking implementation करते समय shared instance reference को volatile रखना जरूरी है।

17. क्या Double-Checked Locking हमेशा best choice है?#

नहीं।

यह correct हो सकती है, लेकिन code comparatively complex है।

अगर requirement को simpler approach solve कर सकती है, तो unnecessarily complex concurrency logic लिखने की जरूरत नहीं है।

Java में एक elegant alternative है:

Initialization-on-Demand Holder Idiom

18. Initialization-on-Demand Holder Idiom#

Implementation:

JAVA
public class AppSettings {

    private AppSettings() {
    }

    private static class Holder {
        private static final AppSettings INSTANCE = new AppSettings();
    }

    public static AppSettings getInstance() {
        return Holder.INSTANCE;
    }
}

पहली नज़र में यह strange लग सकती है।

लेकिन concept simple है।

Outer class load होने से जरूरी नहीं कि nested Holder class उसी समय initialize हो।

जब पहली बार यह line execute होती है:

JAVA
return Holder.INSTANCE;

तब JVM Holder class को initialize करती है।

और उस initialization के दौरान:

JAVA
private static final AppSettings INSTANCE = new AppSettings();

execute होता है।

इससे हमें मिलता है:

  • lazy initialization
  • thread-safe initialization
  • explicit synchronized की जरूरत नहीं
  • Double-Checked Locking जैसी manual concurrency complexity नहीं
Key Idea

Holder idiom thread safety के लिए हमारे handwritten locking logic पर depend नहीं करता। यह Java की class initialization guarantees का लाभ उठाता है।

Plain Java class-based Singleton के लिए यह अक्सर बहुत clean approach है।

19. Enum-Based Singleton#

Java एक और powerful option देता है:

JAVA
public enum ApplicationRegistry {

    INSTANCE;

    public void register(String name) {
        System.out.println("Registered: " + name);
    }
}

Use:

JAVA
ApplicationRegistry.INSTANCE.register("PaymentService");

यहाँ:

JAVA
INSTANCE

enum का single constant है।

इसलिए separate getInstance() method की जरूरत भी नहीं होती।

Enum Singleton के फायदे#

Enum Singleton:

  • concise है
  • JVM-backed initialization guarantees देता है
  • built-in serialization behavior के कारण duplicate instance problem से naturally बचता है
  • ordinary reflective enum construction को Java restrict करता है

इसलिए Java में robust Singleton चाहिए तो enum approach बहुत strong option है।

लेकिन हर API design के लिए enum syntax convenient हो, यह जरूरी नहीं।

20. Eager, Lazy, Holder और Enum की तुलना#

Approach Lazy? Thread-safe? Complexity Important characteristic
Eager No Yes Low Simple and predictable
Naive Lazy Yes No Low Multithreading में unsafe
Synchronized Lazy Yes Yes Low-Medium Every access synchronized
Double-Checked Locking Yes Yes, when correctly implemented with volatile High Avoids synchronization after initialization
Holder Idiom Yes Yes Low-Medium Uses class initialization guarantees
Enum Singleton Effectively initialized with enum class Yes Low Strong Java-specific safety characteristics

21. कौन-सा approach चुनना चाहिए?#

कोई एक implementation हर project के लिए automatically best नहीं है।

Decision requirement पर depend करता है।

Eager चुनें जब#

  • object cheap है
  • object application में निश्चित रूप से use होगा
  • simple implementation चाहिए
  • lazy loading की जरूरत नहीं है

Synchronized Lazy चुनें जब#

  • lazy creation चाहिए
  • simplicity performance micro-optimization से ज्यादा important है
  • accessor बहुत high-frequency bottleneck नहीं है

Holder Idiom चुनें जब#

  • plain Java class-based Singleton चाहिए
  • lazy initialization चाहिए
  • thread safety चाहिए
  • explicit locking complexity avoid करनी है

Enum Singleton चुनें जब#

  • enum representation design के लिए acceptable है
  • robust Java-specific Singleton चाहिए
  • serialization/reflection concerns को minimum रखना है

Double-Checked Locking चुनें जब#

  • आपको specifically lazy initialization चाहिए
  • synchronization-after-initialization avoid करना meaningful है
  • team concurrency semantics को confidently maintain कर सकती है
Tip

सबसे clever implementation चुनना goal नहीं है। सबसे simple correct implementation चुनना बेहतर engineering है।

22. Singleton कब appropriate हो सकता है?#

Singleton तब consider किया जा सकता है जब domain requirement वास्तव में कहती है:

इस application context में इस component की एक controlled shared instance होनी चाहिए।

Possible examples:

  • application-wide immutable configuration holder
  • shared registry
  • process-level coordinator
  • stateless infrastructure helper जिसकी identity intentionally shared हो
  • central application component जिसका duplicate creation वास्तव में incorrect behavior create करेगा

लेकिन यहाँ भी एक सवाल पूछना चाहिए:

क्या हमें सच में Singleton Pattern चाहिए, या केवल shared lifetime चाहिए?

Modern applications में dependency injection container अक्सर shared lifecycle manage कर सकता है, बिना global static access introduce किए।

23. Singleton कब inappropriate है?#

Singleton को केवल convenience के लिए use करना risky है।

User-specific state#

Shopping cart, current user, current request या session data को application-wide Singleton में रखना गलत हो सकता है।

क्यों?

क्योंकि अलग users का state अलग होना चाहिए।

Database Connection#

एक single JDBC Connection को application Singleton बनाना सामान्यतः सही design नहीं है।

Concurrent applications में connection pooling जैसी lifecycle strategy चाहिए होती है।

Mutable Global State#

अगर कई unrelated parts एक Singleton की mutable state modify कर रहे हैं, तो program behavior समझना कठिन हो सकता है।

केवल इसलिए कि object बनाना आसान हो#

अगर reason यह है:

"हर class में dependency pass करने से अच्छा Singleton.getInstance() call कर लेते हैं"

तो यह hidden dependency पैदा कर सकता है।

Future में multiple instances की जरूरत पड़ सकती है#

आज एक configuration है।

कल:

  • multiple tenants
  • multiple environments
  • multiple data sources
  • isolated tests
  • separate plugins

की जरूरत पड़ सकती है।

Global Singleton future design को restrict कर सकता है।

24. Singleton और Global State का संबंध#

Singleton का सबसे बड़ा architectural concern यह है कि वह आसानी से global state बन सकता है।

मान लीजिए:

JAVA
GlobalSettings.getInstance().setMode("TEST");

और application की दस अलग classes:

JAVA
GlobalSettings.getInstance()

use करती हैं।

अब उन classes की behavior एक hidden global object पर depend करती है।

Method signature देखकर dependency दिखाई नहीं देती।

यही hidden dependency debugging और testing मुश्किल बना सकती है।

25. Tight Coupling कैसे पैदा होती है?#

इस code को देखें:

JAVA
public class OrderService {

    public void process() {
        AuditService audit = AuditService.getInstance();
        audit.log("Processing order");
    }
}

OrderService सीधे concrete Singleton से जुड़ गया।

अगर testing में fake audit service use करनी हो, तो आसानी से replace करना मुश्किल हो सकता है।

Dependency injection style में dependency explicit हो सकती है:

JAVA
public class OrderService {

    private final AuditService auditService;

    public OrderService(AuditService auditService) {
        this.auditService = auditService;
    }

    public void process() {
        auditService.log("Processing order");
    }
}

अब dependency constructor में साफ दिखाई देती है।

Test अलग implementation pass कर सकता है।

इसका मतलब यह नहीं कि Dependency Injection हमेशा Singleton के opposite है।

एक DI container स्वयं किसी dependency को single shared instance के रूप में manage कर सकता है।

Difference यह है कि consumers को global static lookup करने की जरूरत नहीं पड़ती।

26. Testing में Singleton problem क्यों बन सकता है?#

Tests ideally independent होने चाहिए।

Test A का state Test B को affect नहीं करना चाहिए।

Mutable Singleton के साथ यह हो सकता है:

  1. Test A Singleton state बदलता है।
  2. state reset नहीं होती।
  3. Test B वही shared state पढ़ता है।
  4. Test B अकेले run करने पर pass होता है।
  5. पूरी suite में run करने पर fail हो जाता है।

इसे test order dependency जैसी problem मिल सकती है।

इसलिए shared mutable Singleton state को बहुत carefully design करना चाहिए।

Common Mistake

Thread-safe Singleton का मतलब automatically test-friendly या good architecture नहीं होता। Thread safety और design quality दो अलग concerns हैं।

27. Serialization Singleton को कैसे तोड़ सकती है?#

मान लीजिए class Serializable है।

Traditional class-based Singleton serialize किया गया।

फिर deserialize किया गया।

Default Java serialization एक नया object produce कर सकती है।

Conceptually:

JAVA
Singleton original = Singleton.getInstance();

// serialization...

Singleton restored = ...;

restored theoretically अलग object बन सकता है।

Traditional serializable Singleton में readResolve() use किया जा सकता है:

JAVA
import java.io.Serializable;

public class Settings implements Serializable {

    private static final long serialVersionUID = 1L;

    private static final Settings INSTANCE = new Settings();

    private Settings() {
    }

    public static Settings getInstance() {
        return INSTANCE;
    }

    private Object readResolve() {
        return INSTANCE;
    }
}

readResolve() deserialization के बाद canonical Singleton instance return करने में मदद करता है।

Enum Singleton में Java की serialization semantics इस concern को naturally handle करती हैं।

28. Reflection से Singleton कैसे break हो सकता है?#

Private constructor सामान्य Java code को रोकता है।

लेकिन reflection का purpose ही runtime metadata inspect और access करना है।

कुछ environments में reflective access से private constructor invoke करने की कोशिश की जा सकती है।

इससे traditional class-based Singleton की assumptions break हो सकती हैं।

इसलिए:

private constructor को absolute security boundary मत समझिए।

कुछ implementations constructor के अंदर defensive checks add करती हैं।

लेकिन ऐसे checks initialization ordering और reflection timing के कारण हमेशा simple universal solution नहीं होते।

अगर reflection resistance एक strong requirement है, तो enum-based Singleton सामान्य traditional implementation से अधिक robust choice है।

29. Multiple Class Loaders वाला Pitfall#

यह advanced लेकिन interview-important detail है।

Java में class identity केवल class name से तय नहीं होती।

Defining class loader भी important होता है।

अगर दो independent class loaders एक ही Singleton class को अलग-अलग load करते हैं, तो दोनों loaded classes के पास अपनी static fields हो सकती हैं।

मतलब:

  • ClassLoader A → INSTANCE A
  • ClassLoader B → INSTANCE B

इसलिए Singleton का guarantee सामान्यतः यह नहीं है:

"पूरे JVM में किसी भी हालत में केवल एक object।"

Better understanding:

एक loaded Singleton class definition के context में controlled single instance।

यह issue plugin systems, application servers, modular systems और complex container environments में relevant हो सकता है।

30. Singleton और Static Utility Class एक ही चीज हैं?#

नहीं।

Static utility class:

JAVA
public final class MathUtil {

    private MathUtil() {
    }

    public static int doubleValue(int value) {
        return value * 2;
    }
}

यहाँ meaningful object instance ही नहीं है।

हम केवल static behavior use कर रहे हैं।

Singleton में actual object होता है।

उस object की:

  • identity हो सकती है
  • state हो सकती है
  • interfaces के साथ design हो सकता है
  • lifecycle हो सकती है

इसलिए:

static utility class ≠ Singleton object

31. एक Practical Singleton Example#

मान लीजिए plain Java application में एक registry चाहिए जिसमें startup के बाद shared service names lookup किए जाएँ।

Holder idiom use कर सकते हैं:

JAVA
import java.util.HashMap;
import java.util.Map;

public class ServiceRegistry {

    private final Map<String, String> services = new HashMap<>();

    private ServiceRegistry() {
    }

    private static class Holder {
        private static final ServiceRegistry INSTANCE =
                new ServiceRegistry();
    }

    public static ServiceRegistry getInstance() {
        return Holder.INSTANCE;
    }

    public void register(String name, String endpoint) {
        services.put(name, endpoint);
    }

    public String find(String name) {
        return services.get(name);
    }
}

Use:

JAVA
public class Main {

    public static void main(String[] args) {

        ServiceRegistry registry =
                ServiceRegistry.getInstance();

        registry.register(
                "payment",
                "https://payment.internal"
        );

        String endpoint =
                ServiceRegistry.getInstance()
                        .find("payment");

        System.out.println(endpoint);
    }
}

यह example Singleton mechanics दिखाता है।

Real concurrent application में registry के mutable HashMap access की अपनी thread-safety requirements भी होंगी।

यहाँ एक important distinction समझें:

Singleton instance creation thread-safe होना और Singleton के अंदर mutable data thread-safe होना अलग-अलग problems हैं।

32. Singleton Thread Safety के दो अलग सवाल#

Beginners अक्सर इन दोनों को mix करते हैं।

क्या केवल एक instance safely create हुई?Show Answer

यह Singleton construction problem है।

Eager initialization, synchronized access, Holder idiom आदि इसे solve कर सकते हैं।

उस object की mutable state concurrent access में safe है?Show Answer

यह object-state concurrency problem है।

इसके लिए अलग techniques चाहिए हो सकती हैं:

  • synchronization
  • locks
  • concurrent collections
  • immutable state
  • atomic operations

Singleton Pattern केवल object count control करके दूसरी problem automatically solve नहीं करता।

Remember

Thread-safe creation ≠ thread-safe internal mutable state.

33. Singleton Overuse कैसे पहचानें?#

अगर project में हर दूसरी service इस तरह दिखने लगे:

JAVA
UserService.getInstance();
PaymentService.getInstance();
EmailService.getInstance();
OrderService.getInstance();
AuditService.getInstance();
CacheService.getInstance();

तो यह warning sign हो सकता है।

Application effectively global service locator बन सकती है।

Dependencies hidden हो जाती हैं।

Testing कठिन हो सकती है।

Alternative के रूप में constructor injection या DI container consider करना चाहिए।

34. Singleton Decision Checklist#

Singleton implement करने से पहले ये questions पूछें:

  1. क्या business या technical invariant वास्तव में single instance मांगता है?
  2. क्या state global होनी चाहिए?
  3. क्या object user/request/session-specific तो नहीं है?
  4. क्या future में multiple configurations या instances चाहिए हो सकती हैं?
  5. क्या dependency injection shared lifetime को cleaner तरीके से manage कर सकता है?
  6. क्या object mutable है?
  7. अगर mutable है, तो concurrent access कैसे handle होगा?
  8. क्या serialization relevant है?
  9. क्या reflection या multiple class loaders वाला environment relevant है?
  10. क्या testing में dependency replace/reset करना आसान रहेगा?

अगर इन questions के अच्छे answers नहीं हैं, तो केवल convenience के कारण Singleton use नहीं करना चाहिए।

35. Common Mistakes#

केवल private constructor लिखकर class को Singleton समझना#

Private constructor सिर्फ external construction रोकता है।

Controlled stored instance और access mechanism भी चाहिए।

Lazy initialization को automatically thread-safe मानना#

यह code:

JAVA
if (instance == null) {
    instance = new Singleton();
}

multithreading में race condition create कर सकता है।

Double-Checked Locking में volatile भूलना#

Correct modern implementation में shared instance reference के लिए volatile critical है।

Singleton के अंदर mutable data को automatically safe मानना#

Safe instance creation और safe state mutation अलग concerns हैं।

हर service को Singleton बना देना#

यह global state और hidden dependency बढ़ा सकता है।

Database connection को Singleton बनाना#

Shared service object और shared physical database connection एक ही design problem नहीं हैं।

पूरे JVM में exactly one object assume करना#

Multiple class loaders अलग copies load कर सकते हैं।

36. Interview Preparation#

Singleton Pattern का intent क्या है?Show Answer

एक strong answer:

Singleton Pattern ensures controlled creation of a single shared instance of a class within its loading context and provides a controlled access point to that instance.

Simple meaning यह है कि callers freely objects create नहीं करते। Class अपनी instance creation control करती है।

Lazy Singleton में race condition कैसे आती है?Show Answer

अगर दो threads लगभग एक ही समय instance == null देखें, तो दोनों object create करने की कोशिश कर सकती हैं।

इसलिए naive lazy initialization multithreaded environment में safe नहीं है।

Double-Checked Locking में volatile क्यों चाहिए?Show Answer

volatile instance reference की visibility और safe publication ordering सुनिश्चित करने में important है।

इसके बिना दूसरे thread द्वारा incompletely published object observe करने का risk conceptually मौजूद हो सकता है।

Holder idiom क्यों popular है?Show Answer

क्योंकि यह:

  • lazy है
  • thread-safe है
  • explicit synchronization नहीं मांगता
  • Java class initialization guarantees use करता है
  • implementation relatively simple रखता है
Enum Singleton का advantage क्या है?Show Answer

Enum-based Singleton Java की special enum guarantees का लाभ उठाता है।

यह serialization और ordinary reflection-related construction pitfalls के खिलाफ traditional class Singleton से अधिक robust है।

Singleton को anti-pattern क्यों कहा जाता है?Show Answer

Singleton Pattern स्वयं हमेशा wrong नहीं है।

Criticism तब आता है जब इसे global mutable state या hidden dependency बनाने के लिए overuse किया जाता है।

इससे:

  • coupling बढ़ सकती है
  • testing difficult हो सकती है
  • state isolation खराब हो सकती है
  • future multiple-instance requirements कठिन हो सकती हैं

37. Chapter Recap#

इस chapter से सबसे important बातें:

  • Singleton का goal uncontrolled object creation रोककर controlled shared instance provide करना है।
  • private constructor external new calls को रोकता है।
  • Eager initialization simple और thread-safe है, लेकिन lazy नहीं है।
  • Naive Lazy Singleton multithreading में unsafe हो सकता है।
  • synchronized accessor simple thread-safe lazy solution है।
  • Double-Checked Locking में two null checks और volatile महत्वपूर्ण हैं।
  • Holder idiom lazy, thread-safe और clean Java solution है।
  • Enum Singleton Java में बहुत robust approach है।
  • Singleton instance safely create होना internal mutable state को automatically thread-safe नहीं बनाता।
  • Global state, hidden dependencies और tight coupling testing और maintenance कठिन बना सकते हैं।
  • Serialization traditional Singleton को duplicate कर सकती है; readResolve() मदद कर सकता है।
  • Reflection traditional private-constructor Singleton को challenge कर सकती है।
  • Multiple class loaders separate Singleton instances बना सकते हैं।
  • Singleton को default convenience mechanism नहीं, deliberate design decision की तरह use करना चाहिए।
Summary

Singleton सीखने का सबसे important lesson केवल "एक object कैसे बनाना है" नहीं है। असली engineering skill यह decide करना है कि एक shared global instance वास्तव में चाहिए भी या नहीं।

Interactive learning

Practice lab

Apply this chapter with guided activities, immediate feedback, explanations, and retry.

Practice loads when this section enters view.