2009-05-18 12 views
123

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

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

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) { 
     // ... 
    } 
} 
+9

मुझे यह डिज़ाइन पसंद नहीं है, क्योंकि यह अवांछित है। निर्भरता इंजेक्शन पर एक नज़र डालें। – dfa

उत्तर

178

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

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

+2

:-) स्पष्ट और सीधे बिंदु पर - चीयर्स! – simon622

+1

हालांकि, एक वर्ग एक से अधिक वर्ग लोडर द्वारा लोड किया जा सकता है तो addController अभी भी (या नहीं, आप कॉल सिंक्रनाइज़ की परवाह किए बिना) एक बार से अधिक कहा जाता है हो सकता है ... –

+4

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

3

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

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

0

हां, स्टेटिक प्रारंभकर्ता केवल एक बार चलते हैं। Read this for more information

+1

नहीं, वे एक से अधिक बार चलाए जा सकते हैं। –

+2

नहीं, वे प्रत्येक क्लासस्पेकर में एक बार चलाए जा सकते हैं। – ruurd

1

हाँ,

एक static प्रारंभकर्ता की तरह केवल एक बार कहा जाता हो जाता है, तो यह है कि परिभाषा यह धागा सुरक्षित है द्वारा - आप static प्रारंभकर्ता के दो या अधिक आमंत्रण आवश्यकता होगी भी धागा विवाद मिलता है।

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

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

+3

एक बहुत ही परिभाषित क्रम है जिसमें उन्हें कहा जाता है: स्रोत कोड में क्रमशः। – mafu

+0

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

+7

कक्षा के भीतर, प्रारंभकर्ता कोड का पालन करते हैं। दो या दो से अधिक कक्षाओं को देखते हुए, यह इतना परिभाषित नहीं किया गया है कि किस वर्ग को पहले आरंभ किया जाता है, चाहे एक वर्ग दूसरे शुरू होने से पहले 100% शुरू हो जाता है, या चीजें कैसे "इंटरलीव" होती हैं। जैसे यदि प्रत्येक वर्ग में प्रत्येक एक दूसरे के संदर्भ में स्थैतिक इनटाइटलियलाइज़र होते हैं, तो चीजें बदसूरत हो जाती हैं। मैंने सोचा था कि शुरुआती आवेदकों का आह्वान करने वाले अन्य वर्गों के लिए एक स्थिर अंतिम int को संदर्भित करने के तरीके थे, लेकिन मैं इस बिंदु पर किसी अन्य तरीके से बहस नहीं कर रहा हूं या – Matt

10

इस रूप में SingletonHolder में स्थिर ब्लॉक एक धागा सुरक्षित तरीके से आप डॉन 'में एक बार चला जाएगा एक चाल आप जावा 5,0

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

आलसी आरंभीकरण

enum Singleton { 
    INSTANCE; 
} 

के लिए या पूर्व के लिए उपयोग कर सकते हैं किसी अन्य लॉकिंग की जरूरत नहीं है। क्लास सिंगलटनहोल्डर केवल तब लोड हो जाएगा जब आप इंस्टेंस कॉल करते हैं()

+18

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

+2

मुझे लगता है कि यह बहु-वर्ग लोडर पर्यावरण में भी सुरक्षित नहीं है। – Ahmad

+0

@ अहमद - जहां तक ​​मैं समझता हूं, हां। तुम सही हो। –

-2

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

संबंधित मुद्दे