क्या जावा स्टैटिक इनिशियलाइज़र थ्रेड सुरक्षित हैं?


136

मैं एक रजिस्ट्री में कुछ नियंत्रकों को शुरू करने के लिए एक स्थिर कोड ब्लॉक का उपयोग कर रहा हूं। मेरा प्रश्न इसलिए है, क्या मैं गारंटी दे सकता हूं कि यह स्थिर कोड ब्लॉक केवल एक बार बुलाया जाएगा जब कक्षा पहली बार भरी जाएगी? मैं समझता हूं कि मैं गारंटी नहीं दे सकता कि यह कोड ब्लॉक कब कहा जाएगा, मैं अनुमान लगा रहा हूं कि क्लास लोडर ने पहले इसे लोड किया था। मुझे लगता है कि मैं स्थिर कोड ब्लॉक में वर्ग पर सिंक्रनाइज़ कर सकता हूं, लेकिन मेरा अनुमान है कि यह वास्तव में वैसे भी क्या होता है?

सरल कोड उदाहरण होगा;

class FooRegistry {

    static {
        //this code must only ever be called once 
        addController(new FooControllerImpl());
    }

    private static void addController(IFooController controller) { 
        // ...
    }
}

या मुझे यह करना चाहिए;

class FooRegistry {

    static {
        synchronized(FooRegistry.class) {
            addController(new FooControllerImpl());
        }
    }

    private static void addController(IFooController controller) {
        // ...
    }
}

10
मुझे यह डिज़ाइन पसंद नहीं है, क्योंकि यह अप्रतिष्ठित है। डिपेंडेंसी इंजेक्शन पर एक नजर।
dfa

जवाबों:


199

हां, जावा स्टैटिक इनिशियलाइज़र थ्रेड सुरक्षित हैं (अपने पहले विकल्प का उपयोग करें)।

हालाँकि, यदि आप यह सुनिश्चित करना चाहते हैं कि कोड को ठीक उसी समय निष्पादित किया जाए, जब आपको यह सुनिश्चित करने की आवश्यकता होती है कि वर्ग केवल एकल श्रेणी-लोडर द्वारा लोड किया गया है। क्लास-लोडर के अनुसार एक बार स्टेटिक इनिशियलाइज़ेशन किया जाता है।


2
हालाँकि, एक क्लास को कई क्लास-लोडर द्वारा लोड किया जा सकता है, इसलिए addController को अभी भी एक से अधिक बार कॉल किया जा सकता है (भले ही आप कॉल को सिंक्रनाइज़ करें या नहीं) ...
मैथ्यू मर्डोक

4
इसके बाद अहा हैंग हो जाता है, इसलिए हम कह रहे हैं कि स्टैटिक कोड ब्लॉक वास्तव में हर क्लास लोडर के लिए कहा जाता है जो क्लास को लोड करता है? हम्म ... मुझे लगता है कि यह अभी भी ठीक होना चाहिए, हालांकि, सोच रहा हूं कि
ओएसजीआई

1
हाँ। स्टैटिक कोड ब्लॉक में क्लास को लोड करने वाले हर क्लास-लोडर को बुलाया जाता है।
मैथ्यू मर्डोक

3
@ simon622 हाँ, लेकिन यह प्रत्येक ClassLoader में एक अलग वर्ग ऑब्जेक्ट में काम करेगा। विभिन्न श्रेणी की वस्तुएँ जिनका अभी भी पूरी तरह से योग्य नाम है, लेकिन विभिन्न प्रकारों का प्रतिनिधित्व करती हैं जिन्हें एक दूसरे के लिए नहीं रखा जा सकता है।
इरविन बोलविड्ट

1
इसका मतलब यह है कि 'अंतिम' कीवर्ड उदाहरण धारक में: en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom में निरर्थक है ?
spc16670

11

यह एक चाल है जिसे आप आलसी आरंभीकरण के लिए उपयोग कर सकते हैं

enum Singleton {
    INSTANCE;
}

या पूर्व जावा 5.0 के लिए

class Singleton {
   static class SingletonHolder {
      static final Singleton INSTANCE = new Singleton();
   }
   public static Singleton instance() {
      return SingletonHolder.INSTANCE;
   }
}

चूंकि सिंगलटन थ्रेड में स्टैटिक ब्लॉक एक बार एक थ्रेड सेफ तरीके से चलेगा, तो आपको किसी अन्य लॉकिंग की आवश्यकता नहीं है। जब आप कॉल () कॉल करते हैं तो क्लास सिंगलटन फ़ोल्डर केवल लोड हो जाएगा


18
आप इस उत्तर को इस तथ्य पर आधारित कर रहे हैं कि स्टेटिक ब्लॉक को केवल एक बार विश्व स्तर पर निष्पादित किया जाएगा - जो कि बहुत ही प्रश्न पूछा गया था।
माइकल मायर्स

2
मुझे लगता है कि यह बहु-वर्ग लोडर वातावरण में सुरक्षित नहीं है कि क्या कहते हैं?
अहमद

2
@ अहमदाबाद मल्टी-क्लास लोडर वातावरण को प्रत्येक एप्लिकेशन को स्वयं के सिंगलटन के लिए अनुमति देने के लिए डिज़ाइन किया गया है।
पीटर लॉरी

4

सामान्य परिस्थितियों में स्टैटिक इनिशियलाइज़र में सब कुछ होता है-उस क्लास का उपयोग करने वाली हर चीज़ से पहले, इसलिए सिंक्रोनाइज़ेशन आमतौर पर आवश्यक नहीं होता है। हालाँकि, क्लास कुछ भी एक्सेस करने योग्य होता है, जिसमें स्टैटिक इंटीलाइज़र कॉल (जिसमें अन्य स्टैटिक इनिशियलाइज़र्स को शामिल किया जाता है) शामिल हैं।

एक वर्ग को भरी हुई कक्षा द्वारा लोड किया जा सकता है लेकिन जरूरी नहीं कि उसे सीधे शुरू किया जाए। बेशक, एक क्लास को क्लास लोडर के कई उदाहरणों द्वारा लोड किया जा सकता है और इस तरह एक ही नाम के साथ कई क्लास बन सकते हैं।


3

हाँ, की तरह

एक staticइनिशियलाइज़र को केवल एक बार कॉल किया जाता है, इसलिए इस परिभाषा के अनुसार यह थ्रेड सुरक्षित है - आपको दो या अधिक इनवोकेशन की आवश्यकता होगीstatic इनिशियलाइज़र के भी यहाँ तक कि थ्रेड कॉनडेशन भी।

उस ने कहा, staticशुरुआती कई अन्य तरीकों से भ्रमित कर रहे हैं। वास्तव में कोई निर्दिष्ट क्रम नहीं है जिसमें उन्हें बुलाया जाता है। यह वास्तव में भ्रामक हो जाता है यदि आपके पास दो वर्ग हैं जिनके staticशुरुआती एक-दूसरे पर निर्भर हैं। और यदि आप एक वर्ग का उपयोग करते हैं, लेकिन उपयोग नहीं करते हैं कि staticइनिशलाइज़र क्या सेट करेगा, तो आपको गारंटी नहीं है कि क्लास लोडर स्टैटिक इनिशियलाइज़र को आमंत्रित करेगा।

अंत में, उन वस्तुओं को ध्यान में रखें जिन्हें आप सिंक्रनाइज़ कर रहे हैं। मुझे एहसास है कि यह वास्तव में आप क्या पूछ रहे हैं, लेकिन सुनिश्चित करें कि आपका प्रश्न वास्तव में नहीं पूछ रहा है कि क्या आपको addController()थ्रेड-सुरक्षित बनाने की आवश्यकता है ।


5
एक बहुत परिभाषित क्रम है जिसमें उन्हें कहा जाता है: स्रोत कोड में आदेश द्वारा।
मफू २०'०

इसके अलावा, उन्हें हमेशा कहा जाता है, भले ही आप उनके परिणाम का उपयोग करें। जब तक यह जावा 6 में नहीं बदला गया था
mafu

8
एक वर्ग के भीतर, इनिशियलाइज़र कोड का पालन करते हैं। दो या दो से अधिक कक्षाओं को देखते हुए, इसे इतना परिभाषित नहीं किया जाता है कि कौन सी कक्षा पहले आरम्भिक हो जाती है, क्या एक वर्ग एक दूसरे के शुरू होने से पहले 100% आरंभिक हो जाता है, या कैसे चीजें "interleaved" होती हैं। उदाहरण के लिए, यदि दो वर्गों में एक-दूसरे का जिक्र करने वाले स्थैतिक अंतर्वाहक हैं, तो चीजें बदसूरत हो जाती हैं। मैंने सोचा था कि ऐसे तरीके हैं जो आप एक स्थिर वर्ग के लिए संदर्भित कर सकते हैं, दूसरे वर्ग w / o में शुरुआती को आमंत्रित कर सकते हैं, लेकिन मैं एक तरह से या किसी अन्य पर बहस नहीं करने जा रहा हूं
मैट

यह बदसूरत हो जाता है, और मैं इससे बचता हूं। लेकिन चक्र कैसे हल किया जाता है, इसके लिए एक परिभाषित तरीका है। "जावा प्रोग्रामिंग लैंग्वेज 4th एडिशन" को उद्धृत करते हुए: पेज: 75, सेक्शन: 2.5.3। स्टैटिक इनिशियलाइज़ेशन: "यदि साइकल होता है, तो X के स्टैटिक इनिशियलाइज़र को केवल उसी बिंदु पर निष्पादित किया जाएगा, जहाँ Y की विधि लागू की गई थी। जब Y, बदले में, X विधि को लागू करता है, तो वह विधि बाकी स्टैटिक इनिशियलाइज़र्स के साथ चलती है, जिसे अभी निष्पादित नहीं किया गया है। "
जेएमआई मैडिसन

0

हां, स्टेटिक इनिशियलाइज़र केवल एक बार चलाया जाता है। अधिक जानकारी के लिए इसे पढ़ें


2
नहीं, उन्हें एक से अधिक बार चलाया जा सकता है।
सीमित प्रायश्चित

5
नहीं वे एक बार प्रति वर्ग के अनुसार चलाए जा सकते हैं।
बर्बाद

मूल उत्तर: स्टेटिक इनिट केवल एक बार चलता है। उन्नत उत्तर: स्टेटिक इनिट एक बार प्रति क्लास लोडर चलता है। पहली टिप्पणी भ्रामक है क्योंकि इन दो उत्तरों को मिलाना फिजूलखर्ची है।
जेएमआई मैडिसन

-4

इसलिए मूल रूप से, चूंकि आप एक सिंगलटन उदाहरण चाहते हैं, इसलिए आपको इसे पुराने जमाने के तरीके से कम या ज्यादा करना चाहिए और यह सुनिश्चित करना चाहिए कि आपकी सिंगलटन ऑब्जेक्ट को एक बार और केवल एक बार शुरू किया जाए।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.