2010-03-25 9 views
13

मेरे earlier question on incompletely constructed objects का जिक्र करते हुए, मेरे पास दूसरा प्रश्न है। जैसा कि जॉन स्कीट ने बताया, एक निर्माता के अंत में एक अंतर्निहित स्मृति बाधा है जो सुनिश्चित करता है कि final फ़ील्ड सभी धागे के लिए दृश्यमान हैं। लेकिन क्या होगा अगर एक कन्स्ट्रक्टर दूसरे कन्स्ट्रक्टर को कॉल करता है; उनमें से प्रत्येक के अंत में ऐसी याददाश्त बाधा है, या केवल उस व्यक्ति के अंत में जिसे पहली जगह बुलाया गया है?रचनाकारों को चेन करते समय जेवीएम की अंतर्निहित स्मृति बाधाएं कैसे व्यवहार करती हैं?

public class ThisEscape { 
    public ThisEscape(EventSource source) { 
     source.registerListener(
      new EventListener() { 
       public void onEvent(Event e) { 
        doSomething(e); 
       } 
      }); 
    } 
} 

और सही एक कारखाने विधि संस्करण होगा:

public class SafeListener { 
    private final EventListener listener; 

    private SafeListener() { 
     listener = new EventListener() { 
      public void onEvent(Event e) { 
       doSomething(e); 
      } 
     } 
    } 

    public static SafeListener newInstance(EventSource source) { 
     SafeListener safe = new SafeListener(); 
     source.registerListener(safe.listener); 
     return safe; 
    } 
} 

चाहेंगे निम्नलिखित काम भी, या नहीं है कि, जब "गलत" समाधान है?

public class MyListener { 
    private final EventListener listener; 

    private MyListener() { 
     listener = new EventListener() { 
      public void onEvent(Event e) { 
       doSomething(e); 
      } 
     } 
    } 

    public MyListener(EventSource source) { 
     this(); 
     source.register(listener); 
    } 
} 

अद्यतन: आवश्यक सवाल है कि this() वास्तव में कॉल निजी निर्माता ऊपर (इस स्थिति में वहाँ बाधा जहां इरादा है और सब कुछ सुरक्षित हो जाएगा) के लिए गारंटी है, या यह संभव है कि निजी कन्स्ट्रक्टर को को एक मेमोरी बाधा को बचाने के लिए ऑप्टिमाइज़ेशन के रूप में इनलाइन किया गया है (जिस स्थिति में सार्वजनिक कन्स्ट्रक्टर के अंत तक बाधा नहीं होगी)?

क्या this() के नियम ठीक से कहीं परिभाषित हैं? यदि नहीं, तो मुझे लगता है कि हमें यह मानना ​​चाहिए कि जंजीर रचनाकारों को रेखांकित करने की अनुमति है, और शायद कुछ JVMs या शायद javac एस भी कर रहे हैं।

उत्तर

5

मुझे लगता है कि यह सुरक्षित है जावा स्मृति मॉडल के रूप में कहा गया है कि:

एक वस्तु हो, और के लिए एक निर्माता हो जो एक अंतिम क्षेत्र में लिखा है। अंतिम क्षेत्र एफ होता है जब सी सामान्य रूप से या अचानक से बाहर निकलता है। ध्यान दें कि यदि एक कन्स्ट्रक्टर एक और कन्स्ट्रक्टर का आह्वान करता है, और आमंत्रित कन्स्ट्रक्टर अंतिम फ़ील्ड सेट करता है, तो अंतिम फ़ील्ड के लिए फ्रीज आवेदक कन्स्ट्रक्टर के अंत में होता है।

+1

यह एकमात्र उत्तर है जो आधिकारिक संदर्भ के साथ समर्थित है। (यहां संदर्भ के लिए एक वास्तविक लिंक है: http://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html)। केवल एक चीज मुझे आश्चर्य है कि क्या * फ्रीज * बिल्कुल मतलब है कहीं भी समझाया नहीं गया है (या कम से कम मुझे यह नहीं मिला)। –

+1

मुझे एक ही समस्या थी, एक अनौपचारिक वर्णन है (http://www.cs.umd.edu/~pugh/java/memoryModel/CommunityReview.pdf), एक और औपचारिक परिभाषा में पाया जा सकता है (http: // www.cs.umd.edu/~pugh/java/memoryModel/newFinal.pdf) –

3

इसके कन्स्ट्रक्टर समाप्त होने पर एक ऑब्जेक्ट को पूरी तरह से प्रारंभ किया जाना माना जाता है।

यह जंजीर रचनाकारों के लिए भी लागू होता है।

यदि आपको कन्स्ट्रक्टर में पंजीकरण करना है तो श्रोता को स्थिर आंतरिक कक्षा के रूप में परिभाषित करें। यह सुरक्षित है।

+2

क्या आप सुनिश्चित हैं कि संकलक यह नहीं पता कि निजी निर्माता को किसी अन्य निर्माता से बुलाया जा रहा है, और फिर वास्तव में कॉल करने की बजाय, यह एक स्मृति को बचाने के लिए कॉलिंग (सार्वजनिक) कन्स्ट्रक्टर में रेखांकित होगा बाधा? –

1

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


मेरा अनुमान है कि यह नाजुक लेकिन ठीक होगा। संकलक यह नहीं जान सकता कि आंतरिक कन्स्ट्रक्टर को केवल अन्य रचनाकारों के भीतर ही बुलाया जाएगा या नहीं, इसलिए यह सुनिश्चित करना होगा कि कोड केवल आंतरिक कन्स्ट्रक्टर को कॉल करने के लिए सही होगा, इसलिए जो भी तंत्र इसका उपयोग करता है (स्मृति बाधा?) है वहां जगह बनने के लिए।

मुझे लगता है कि संकलक प्रत्येक कन्स्ट्रक्टर के अंत में मेमोरी बाधा जोड़ देगा। समस्या अभी भी वहां है: आप this को अन्य कोड (संभावित रूप से अन्य धागे) के संदर्भ में पूरी तरह से निर्मित होने से पहले गुजर रहे हैं - यह बुरा है - लेकिन यदि केवल 'कन्स्ट्रक्शन' छोड़ा गया है तो श्रोता को पंजीकृत करना है, फिर ऑब्जेक्ट स्टेटस जितना स्थिर होगा उतना स्थिर होगा।

समाधान नाजुक कि में किसी और दिन है, तो आप या कुछ अन्य प्रोग्रामर वस्तु के लिए एक और सदस्य को शामिल करने में क्षेत्र प्रारंभ करने का फैसला कर सकता की आवश्यकता हो सकती है और कहा कि श्रृंखलित कंस्ट्रक्टर्स संगामिति चाल है भूल सकते हैं और सार्वजनिक कन्स्ट्रक्टर, और ऐसा करने से आपके एप्लिकेशन में संभावित डेटा रेस का पता लगाने में कठिनाई होगी, इसलिए मैं उस निर्माण से बचने की कोशिश करूंगा।

बीटीडब्ल्यू: अनुमानित सुरक्षा गलत हो सकती है। मुझे नहीं पता कि संकलक कितना जटिल/स्मार्ट है, और क्या मेमोरी बाधा (या जैसा) कुछ ऐसा है जो इसे अनुकूलित करने का प्रयास कर सकता है ... क्योंकि कन्स्ट्रक्टर निजी है क्योंकि संकलक के पास पर्याप्त जानकारी है कि यह जानना है कि यह है केवल अन्य रचनाकारों से ही बुलाया जाता है, और यह निर्धारित करने के लिए पर्याप्त जानकारी है कि आंतरिक कन्स्ट्रक्टर में सिंक्रनाइज़ेशन तंत्र आवश्यक नहीं है ...

+0

"कंपाइलर यह नहीं जान सकता कि आंतरिक कन्स्ट्रक्टर को केवल अन्य रचनाकारों के भीतर ही बुलाया जाएगा या नहीं, इसलिए यह सुनिश्चित करना होगा कि कोड केवल आंतरिक कन्स्ट्रक्टर को कॉल करने के लिए सही होगा।" - बहुत अच्छी सोच, धन्यवाद! जब तक कि संकलक का पता नहीं लगाता कि आंतरिक कन्स्ट्रक्टर को किसी अन्य निर्माता से बुलाया जा रहा है, और फिर वास्तव में आंतरिक कन्स्ट्रक्टर को कॉल करने की बजाय, यह इसे सार्वजनिक रूप से रेखांकित करेगा ... लेकिन उम्मीद है कि ऐसे कोई अनुकूलन नहीं हैं :-) –

+0

वहां आपके पास है: मैंने कन्स्ट्रक्टर के * इनलाइनिंग * में नहीं सोचा था, लेकिन यह काफी सरल अनुकूलन है कि अधिकांश वर्तमान कंपाइलर्स वास्तव में प्रदर्शन कर सकते हैं। तो जवाब होना चाहिए: ऐसा मत करो। –

1

सी-टोर में ऑब्जेक्ट संदर्भ से बचने से एक अपूर्ण रूप से निर्मित ऑब्जेक्ट प्रकाशित हो सकता है। यह भी सच है यदि प्रकाशन निर्माता में अंतिम विवरण है।

आपका सेफलिस्टर एक समवर्ती वातावरण में ठीक व्यवहार नहीं कर सकता है, भले ही सी-टोर इनलाइनिंग की जाती है (जो मुझे लगता है कि यह नहीं है - निजी सी-टोर तक पहुंच करके प्रतिबिंब का उपयोग करके वस्तुओं को बनाने के बारे में सोचें)।

+0

"आपका सेफलिस्टर एक समवर्ती वातावरण में ठीक व्यवहार नहीं कर सकता है, भले ही सी-टोर इनलाइनिंग की जाती है" - मुझे लगता है कि 'सेफलिस्टनर' ठीक व्यवहार करेगा, यह अभ्यास में जावा कंसुरेंसी के अनुसार किया जाना चाहिए। लेकिन 'MyListener' निश्चित रूप से व्यवहार नहीं करेगा अगर इनलाइनिंग की जाती है। इसके अलावा, भले ही निजी कन्स्ट्रक्टर को प्रतिबिंब के माध्यम से "जैसा है" तक पहुंचा जा सके, या संलग्न वर्ग की किसी अन्य विधि के माध्यम से, यह गारंटी नहीं देता है कि निर्माता अन्य रचनाकारों (उसी वर्ग के) कॉलिंग में शामिल नहीं होगा यह। –

3

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

निहित प्रश्न को हल करने के लिए, निर्माण के अंत में बाधा केवल वस्तु निर्माण के अंत में होती है। इनलाइनिंग के बारे में दी गई एक पाठक अंतर्ज्ञान एक उपयोगी है; जावा मेमोरी मॉडल के परिप्रेक्ष्य से, विधि सीमाएं मौजूद नहीं हैं।

+0

मुझे लगता है कि आपका मतलब है कि * तीसरा * संस्करण ('MyListener') सही नहीं है? दूसरा संस्करण जेसीआईपी से है, 'इस' को बचने से रोकने के लिए कहा। लेकिन धन्यवाद! तो 'यह() 'को कॉल करना एक कन्स्ट्रक्टर कॉल नहीं है, यह इस अर्थ में है कि यह ** ** ** ऑब्जेक्ट को पूरी तरह से निर्मित नहीं करता है; ऑब्जेक्ट पूरी तरह से कन्स्ट्रक्टर के बाद ही बनाया गया है, जिसे पहले स्थान पर बुलाया जाता है, रिटर्न। –

+2

रुको। 17.5.1 (गैर-मानक चर्चा में) आंकड़े "ध्यान दें कि यदि एक कन्स्ट्रक्टर दूसरे कन्स्ट्रक्टर को आमंत्रित करता है, और आमंत्रित कन्स्ट्रक्टर अंतिम फ़ील्ड सेट करता है, तो अंतिम क्षेत्र के लिए फ्रीज आवेदक कन्स्ट्रक्टर के अंत में होता है।" यह इंगित करता है कि अंतिम उदाहरण सुरक्षित है। वास्तव में क्या कार्यान्वयन वास्तव में एक पूरी तरह से अलग बात है। –

+0

@ टॉम: वाह! यह वास्तव में कहता है कि। क्या वह आधिकारिक कल्पना नहीं है? तो कार्यान्वयन इसे इस तरह से करना चाहिए, या अन्यथा वे टूट गए हैं। –

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