2013-04-19 5 views
16

का अनुचित प्रकाशन निम्न उदाहरण ब्रायन गोएट्ज़, चैप्टे 3, सेक्शन 3.5.1 द्वारा "जावा कंसुरेंसी इन प्रैक्टिस" पुस्तक से है। यह वस्तुओंजावा ऑब्जेक्ट रेफरेंस

class someClass { 
    public Holder holder; 

    public void initialize() { 
     holder = new Holder(42); 
    } 
} 

public class Holder { 
    private int n; 
    public Holder(int n) { this.n = n; } 

    public void assertSanity() { 
    if (n!=n) 
     throw new AssertionError("This statement is false"); 
    } 
} 

का अनुचित प्रकाशन का उदाहरण इसमें कहा गया है कि धारक और एक असंगत स्थिति में एक और धागा को दिखाया जा सकता है एक और धागा पर्यवेक्षक एक आंशिक रूप से निर्माण वस्तु सका है। ये केसे हो सकता हे? क्या आप उपर्युक्त उदाहरण का उपयोग कर परिदृश्य दे सकते हैं?

यह भी ऐसे मामले भी हैं कि कहने के लिए जब एक धागा एक बासी मूल्य पहली बार यह एक क्षेत्र है और फिर एक अधिक तक दिनांक मान अगली बार है, जिसके कारण assertSanity अभिकथन त्रुटि फेंक कर सकते हैं पढ़ता देख सकते हैं पर चला जाता है। दावा कैसे फेंक दिया जा सकता है?

भविष्य में पढ़ने से, इस समस्या को ठीक करने का एक तरीका है धारक को 'एन' फाइनल बनाकर अपरिवर्तनीय बनाना है। अभी के लिए, मान लें कि धारक अपरिवर्तनीय नहीं है लेकिन प्रभावी रूप से अपरिवर्तनीय है। इस ऑब्जेक्ट को सुरक्षित रूप से प्रकाशित करने के लिए, क्या हमें धारक प्रारंभिक स्थिर बनाना है और इसे अस्थिर (दोनों स्थिर intialization और अस्थिर या केवल अस्थिर) घोषित करना है? कुछ

public class someClass { 
    public static volatile Holder holder = new Holder(42); 

} 

अग्रिम में आपकी सहायता के लिए धन्यवाद।

+2

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

+0

http://www.ibm.com/developerworks/java/library/j-jtp0618/ उपयोगी हो सकता है। –

+3

@PaulGrime - एक संक्षिप्त समीक्षा के बाद मैंने उपरोक्त परिदृश्य को संबोधित करने वाले कुछ भी नहीं देखा। वस्तु का निर्माण करने से पहले संदर्भ "भागने" नहीं है। Int 'n' सार्वजनिक नहीं है और कक्षा के बाहर नहीं देखा जा सकता है। –

उत्तर

9

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

खैर झामुमो लिखने और holder के सदस्य क्षेत्रों के प्रकाशन होने से पहले initialie() में होने वाली के रूप में holder क्षेत्र के लिखने के लिए कोई नियम नहीं है। इसका मतलब यह है कि भले ही holder शून्य नहीं है, सदस्य फ़ील्ड के लिए यह कानूनी है कि अभी तक अन्य धागे के लिए दृश्यमान न हो।

आप की तरह

public class Holder{ 
    String someString = "foo"; 
    int someInt = 10; 
} 

holder शून्य नहीं हो सकता कुछ देखकर खत्म हो सकता है लेकिन someString अशक्त हो सकता है और someInt 0.

हो सकता है एक x86 मेहराब यह है के तहत, जो मैं जानता हूँ से, ऐसा करना असंभव है लेकिन दूसरों में मामला नहीं हो सकता है।

तो अगला प्रश्न Why does volatile fix this? हो सकता है जेएमएम का कहना है कि सभी लिखते हैं कि अस्थिर दुकान से पहले होने वाले अस्थिर क्षेत्र के सभी बाद के धागे दिखाई देते हैं।

तो holder अस्थिर है और आप holder अस्थिर नियमों के आधार पर शून्य नहीं हैं, सभी फ़ील्ड प्रारंभ किए जाएंगे।

सुरक्षित रूप से इस वस्तु को प्रकाशित करने के लिए, हम धारक प्रारंभ स्थिर बनाने के लिए और की घोषणा के रूप में अस्थिर

हाँ, क्योंकि जैसा कि मैंने उल्लेख किया है, तो holder चर रिक्त नहीं है तो सभी राईट होगा की क्या ज़रूरत है दिखाई।

दावा कैसे किया जा सकता है?

एक धागा नोटिस नहीं holder बातिल होने के लिए, और विधि में प्रवेश करने और पढ़ने n पहली बार 0 (डिफ़ॉल्ट मान) हो सकता है पर assertionError का आह्वान करते हैं, तो n की दूसरी पढ़ने अब से लिखने देख सकते हैं पहला धागा

+0

आपके विस्तृत उत्तर के लिए धन्यवाद, यह बहुत समझ में आता है। तो क्या आप कह रहे हैं कि धारक को अस्थिर और स्थैतिक रूप से प्रारंभिक होना चाहिए या केवल अस्थिर होना पर्याप्त है? – GJ13

+1

इन-लाइन स्थैतिक प्रारंभिक वास्तव में अस्थिर के बिना ठीक है (यदि यह मामला सिर्फ इसे अंतिम बनाता है), ऐसा इसलिए है क्योंकि क्लास प्रारंभिक (ऑब्जेक्ट प्रकाशन नहीं) होता है-कक्षा का उपयोग करने से पहले। यदि यह स्थैतिक नहीं था तो 'अस्थिर' + नॉन-नल चेक पर्याप्त होगा। –

+0

'इस पर थोड़ा विस्तार करने के लिए' क्योंकि क्लास प्रारंभिकरण (ऑब्जेक्ट प्रकाशन नहीं होता है) कक्षा का उपयोग करने से पहले होता है 'सभी लिखते हैं जो पूरी तरह से शुरू होने वाली कक्षा से पहले होते हैं, कक्षा के उपयोग के बाद थ्रेड के लिए दृश्यमान होते हैं। –

-1

Holder वर्ग ठीक है, लेकिन वर्ग someClass एक inconsisten राज्य में प्रदर्शित कर सकते हैं - निर्माण और कॉल initialize() करने के लिए holder उदाहरण चर null है के बीच।

+0

हाँ, टीआईएल; लेकिन मैं अपनी खुद की पोस्ट को कम नहीं कर सकता और इसे हटाना नहीं चाहता ... ओह ठीक है। –

2
public class Holder { 
    private int n; 
    public Holder(int n) { this.n = n; } 

    public void assertSanity() { 
    if (n!=n) 
     throw new AssertionError("This statement is false"); 
    } 
} 

एक धागा Holder का एक उदाहरण बनाता है, और एक और धागा है, जो assertSanity कॉल के संदर्भ में गुजरता है कहो।

कन्स्ट्रक्टर में this.n को असाइनमेंट एक थ्रेड में होता है। और n के दो पढ़े एक और धागे में होते हैं। केवल एक ही होता है- यहां संबंधों के संबंध में दो पढ़ने के बीच है। असाइनमेंट और किसी भी पाठ को शामिल करने से पहले कोई संबंध नहीं होता है।

किसी भी तरह के संबंधों के बिना, बयानों को विभिन्न तरीकों से फिर से व्यवस्थित किया जा सकता है, इसलिए एक थ्रेड के परिप्रेक्ष्य से, this.n = n कन्स्ट्रक्टर लौटने के बाद हो सकता है।

इसका मतलब है कि पहले पढ़ने के बाद और दूसरे से पहले असाइनमेंट दूसरे धागे में दिखाई दे सकता है, जिसके परिणामस्वरूप असंगत मूल्य होते हैं। n फ़ाइनल बनाकर इसे रोका जा सकता है, जो गारंटी देता है कि कन्स्ट्रक्टर खत्म होने से पहले मान सौंपा गया है।

0

समस्या है जो आप के बारे में पूछने JVM अनुकूलन द्वारा और कारण होता है तथ्य यह है कि सरल ऑब्जेक्ट निर्माण:

MyClass obj = new MyClass() 

हमेशा कदम से नहीं किया जाता है: के नए उदाहरण के लिए

  1. रिजर्व स्मृति हीप पर MyClass
  2. आंतरिक गुण मान सेट करने के लिए कन्स्ट्रक्टर निष्पादित करें
  3. हीप
  4. 01 पर पते पर 'obj' संदर्भ सेट करें

कुछ अनुकूलन प्रयोजनों के लिए JVM कदम से यह कर सकते हैं:

    ढेर
  1. सेट 'obj' संदर्भ पर MyClass का नया उदाहरण
  2. निष्पादित निर्माता ढेर पर ठीक करने के लिए
  3. रिजर्व स्मृति आंतरिक गुण मान सेट करने के लिए

तो, कल्पना करें कि क्या दो धागे MyClass ऑब्जेक्ट तक पहुंचना चाहते हैं। पहला इसे बनाता है लेकिन JVM के कारण यह चरणों के 'अनुकूलित' सेट को निष्पादित करता है। यदि यह गंभीर समस्या हो सकती है तो यह केवल चरण 1 और 2 निष्पादित करेगा (लेकिन 3 नहीं करेगा)। यदि दूसरा धागा इस ऑब्जेक्ट का उपयोग करता है (यह शून्य नहीं होगा क्योंकि यह पहले ही हीप पर स्मृति के आरक्षित हिस्से को इंगित करता है) इसकी गुण गलत होगी जो खराब चीजों का कारण बन सकती है।

यह अनुकूलन तब नहीं होगा जब संदर्भ अस्थिर हो।

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