2012-01-14 4 views
12

इस साइट पढ़ना, मैं this पाया है:यह स्थिर अंतिम चर एक सिंगल थ्रेड-सुरक्षित में क्यों है?

[यह] लाइन private static final Foo INSTANCE = new Foo(); केवल निष्पादित किया जाता है जब वर्ग वास्तव में प्रयोग किया जाता है, इस आलसी इन्स्टेन्शियशन का ख्याल रखता है, और यह धागा सुरक्षित होने की गारंटी है।

यह थ्रेड सुरक्षित होने की गारंटी क्यों है? क्योंकि यह फ़ील्ड अंतिम है? या किसी अन्य कारण के लिए?

उत्तर

21

क्योंकि यह अंतिम है, हां। अंतिम चर के पास विशेष थ्रेड-सुरक्षा अर्थशास्त्र होते हैं, उस अन्य धागे में कम से कम उस राज्य में अंतिम क्षेत्र को देखने की गारंटी दी जाती है जब यह उसके कन्स्ट्रक्टर समाप्त हो गया था।

यह JLS 17.5 में है, हालांकि भाषा थोड़ी घनी है। ये अर्थशास्त्र जावा 1.5 में विशेष रूप से JSR-133 द्वारा पेश किए गए थे। जेएसआर -133 और इसके विभिन्न प्रभावों की गैर-विशिष्ट चर्चा के लिए यह पृष्ठ देखें।

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

मुझे काफी यकीन है (हालांकि 100% नहीं) यह तथ्य है कि कक्षा प्रारंभिकता केवल एक धागा एक कारक नहीं है। यह सच है कि कक्षा केवल एक थ्रेड द्वारा शुरू की जाती है, लेकिन मुझे विश्वास नहीं है कि किसी भी विशिष्ट होता है- उस धागे के बीच स्थापित किनारों से पहले किसी भी अन्य थ्रेड जो क्लास का उपयोग करता है (अन्य थ्रेड के अलावा पुन: प्रारंभ करने के अलावा कक्षा)। तो, final कीवर्ड के बिना, एक और धागा ऑब्जेक्ट का आंशिक रूप से निर्मित उदाहरण देखने में सक्षम होगा। विशिष्ट होता है- इससे पहले कि जेएमएम परिभाषा JLS 17.4.5 में हैं, और कक्षा प्रारंभिक सूची सूचीबद्ध नहीं है।

+0

हाँ, धन्यवाद। महान उत्तर – MyTitle

+0

मेरा मानना ​​है कि अंतिम से अधिक महत्वपूर्ण कारण यह है कि कक्षा प्रारंभिक (स्थिर प्रारंभिक) को सिंक्रनाइज़ किया जाना चाहिए और थ्रेड सुरक्षित होना चाहिए। यह सिंक्रनाइज़ेशन का उपयोग करते हुए ऑर्डर करने से पहले होता है। अधिक जानकारी के लिए 12.4.2 (http://java.sun.com/docs/books/jls/third_edition/html/execution.html#12.4.2) देखें। – sjlee

+0

@sjlee यह सच है कि प्रारंभिकरण को ताले की आवश्यकता होती है, लेकिन यदि थ्रेड ए MyClass को प्रारंभ करता है, और थ्रेड बी लगभग 5 मिनट बाद आता है और MyClass का उपयोग करता है, तो थ्रेड बी MyClass को प्रारंभ करने का प्रयास नहीं करेगा (क्योंकि यह पहले ही प्रारंभ हो चुका है)। इसका मतलब है कि यह 'MyClass.class' पर लॉक नहीं प्राप्त करेगा, जिसका अर्थ है कि थ्रेड ए के कार्यों और थ्रेड बी के बीच संबंधों से पहले ऐसा नहीं होता है। यदि हर धागे ने इसे 'MyThread.class' पर लॉक किया था, जब भी इसे इस्तेमाल किया जाता था, तो आपको संबंधों से पहले किसी भी अन्य घटना को स्थापित करने की आवश्यकता नहीं होगी। – yshavit

2

किसी भी वर्ग का स्थैतिक प्रारंभिक ब्लॉक एकल थ्रेडेड होने की गारंटी है। एक सरल सिंगलटन एक enum

enum Singleton { 
    INSTANCE; 
} 

यह भी है सुरक्षित थ्रेड और वर्ग आलसी-initialised उपयोग करने के लिए है।

+0

इसके लिए संदर्भ, उदा। JLS? – paislee

+0

@paislee: मैं जेवीएमएस में घर पर अधिक हूं इसलिए मैं आपको [उस संदर्भ के लिए] प्रदान कर सकता हूं (http://java.sun.com/docs/books/jvms/second_edition/html/Concepts.doc। एचटीएमएल # 24,237)। यदि आप प्रक्रिया का पालन करते हैं तो आप देखते हैं कि क्लास प्रारंभिक केवल एक थ्रेड (प्रति क्लासलोडर) द्वारा किया जा सकता है। स्थाई प्रारंभकर्ता को चरण 8 में बुलाया जाता है। – musiKk

+1

जेवीएमएस विभिन्न तरीकों से जेएलएस की तुलना में कठोर अर्थशास्त्र प्रदान करता है, इसलिए यह सामान्य भाषा शुद्धता के लिए एक महान स्रोत नहीं है। जेएलएस [जेएलएस 12.4] (http://java.sun.com/docs/books/jls/third_edition/html/execution.html#12.4) में क्लास प्रारंभिकरण को परिभाषित करता है, और 12.4.2 विशेष रूप से प्रक्रिया का विवरण देता है। – yshavit

3

यह थ्रेड सुरक्षित होने की गारंटी है क्योंकि JVM गारंटी देता है कि स्थैतिक प्रारंभकर्ता एक थ्रेड पर निष्पादित होते हैं।

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

5

कक्षा निर्माणकर्ता और स्थिर/उदाहरण initializers atomically निष्पादित करने की गारंटी दी जाती है और private static final FOO INSTANCE = new FOO; के बाद से

private static final FOO INSTANCE; 

static{ 
    INSTANCE = new FOO(); 
} 

इस मामले से ऊपर श्रेणी में आती है के बराबर है।

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