2009-10-30 10 views
19

प्रत्येक जावा Object में wait() और notify() (और अतिरिक्त रूप) हैं। मैंने कभी इनका उपयोग नहीं किया है और मुझे संदेह है कि कई अन्य लोगों ने नहीं किया है। ये इतने मौलिक क्यों हैं कि प्रत्येक ऑब्जेक्ट को उन्हें रखना होता है और क्या उनमें कोई प्रदर्शन होता है (संभवतया उनमें कुछ राज्य संग्रहीत होता है)?सभी जावा ऑब्जेक्ट्स का इंतजार क्यों है() और सूचित करें() और क्या इससे कोई प्रदर्शन प्रभावित होता है?

प्रश्न पर जोर देने के लिए संपादित करें। अगर मेरे पास List<Double> है जिसमें 100,000 तत्व हैं तो प्रत्येक Double में इन विधियों के रूप में यह Object से बढ़ाया गया है। लेकिन ऐसा लगता है कि इन सभी को List प्रबंधित करने वाले धागे के बारे में पता होना चाहिए।

संपादित करें उत्कृष्ट और उपयोगी उत्तर। @ जोन का एक बहुत अच्छा ब्लॉग पोस्ट है जिसने मेरी आंत भावनाओं को क्रिस्टलाइज किया है। मैं @Bob_Cross के साथ पूरी तरह से सहमत हूं कि आपको इसके बारे में चिंता करने से पहले एक प्रदर्शन समस्या दिखानी चाहिए। (सफल भाषाओं के एनएच कानून के रूप में यदि यह प्रदर्शन प्रदर्शन किया गया तो सूर्य या कोई इसे ठीक कर देता)।

+0

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

+0

@ केविन - धन्यवाद। संपादित करेंगे –

उत्तर

32

ठीक है, तो इसका मतलब यह है कि हर वस्तु को संभावित इसके साथ जुड़े एक मॉनिटर है है है। उसी मॉनिटर का उपयोग synchronized के लिए किया जाता है। यदि आप किसी ऑब्जेक्ट पर सिंक्रनाइज़ करने में सक्षम होने के निर्णय से सहमत हैं, तो wait() और notify() कोई और प्रति-ऑब्जेक्ट स्थिति न जोड़ें। JVM वास्तविक मॉनीटर को आलसी आवंटित कर सकता है (मुझे पता है .NET करता है) लेकिन ऑब्जेक्ट से कौन सा मॉनिटर जुड़ा हुआ है, यह कहने के लिए कुछ स्टोरेज स्पेस उपलब्ध होना चाहिए। माना जाता है कि यह संभव है कि यह एक बहुत ही छोटी राशि (उदाहरण के लिए 3 बाइट्स) है जो वास्तव में ऑब्जेक्ट ओवरहेड के पैडिंग के कारण किसी भी मेमोरी को सहेज नहीं लेती है - आपको यह देखना होगा कि प्रत्येक व्यक्तिगत जेवीएम ने मेमोरी को कैसे संभाला पक्का।

ध्यान दें कि सिर्फ अतिरिक्त तरीकों प्रदर्शन को प्रभावित नहीं करता होने (कोड स्पष्ट की वजह से बहुत थोड़ा के अलावा अन्य उपस्थित कहीं जा रहा है)। यह प्रत्येक ऑब्जेक्ट की तरह नहीं है या यहां तक ​​कि प्रत्येक प्रकार की wait() और notify() के लिए कोड की अपनी प्रति है। Vtables कैसे काम करते हैं, इस पर निर्भर करता है कि प्रत्येक प्रकार प्रत्येक विरासत विधि के लिए एक अतिरिक्त vtable प्रविष्टि के साथ समाप्त हो सकता है - लेकिन यह अभी भी केवल प्रति प्रकार के आधार पर है, प्रति ऑब्जेक्ट आधार पर नहीं। यह मूल रूप से वास्तविक वस्तुओं के लिए भंडारण के थोक की तुलना में शोर में खोने जा रहा है।

व्यक्तिगत रूप से, मुझे लगता है कि दोनों।नेट और जावा ने प्रत्येक ऑब्जेक्ट के साथ मॉनीटर को जोड़कर गलती की - इसके बजाय मुझे स्पष्ट सिंक्रनाइज़ेशन ऑब्जेक्ट्स चाहिए। मैंने blog post about redesigning java.lang.Object/System.Object में इस पर कुछ और लिखा था।

+1

@ जोन धन्यवाद - यह भी मेरा लेना था। –

+1

हॉटस्पॉट ऑब्जेक्ट के लिए मॉनीटर आवंटित नहीं कर सकता है, जब तक कि यह हाथों को न बदल जाए। (आईबीएम वीएम भी वही है)। यदि ऐसा है, तो यह ऑब्जेक्ट हेडर को बढ़ाता है और म्यूटेक्स आवंटित करता है। आम तौर पर बिना शर्त सेंकिसिस बहुत सस्ते (http://java.sun.com/performance/reference/whitepapers/6_performance.html#2.1.1)। प्रतीक्षा करें/सूचित करें अंतिम (और अधिकतर देशी) हैं, इसलिए वे किसी भी VTable में भाग नहीं लेते हैं। – bestsss

+0

@bestsss: "ऑब्जेक्ट हेडर को फुलाकर" इसका क्या मतलब है? क्या ऑब्जेक्ट हेडर अलग-अलग आकार का है? ओह। .NET में, मेरा मानना ​​है कि मॉनिटर केवल ऑन-डिमांड आवंटित किया जाता है (और फिर, यदि कोई विवाद नहीं होता है, तो इसे आम तौर पर आवंटित करने की आवश्यकता नहीं होती है) लेकिन मुझे नहीं लगता कि ऑब्जेक्ट हेडर आकार में परिवर्तन होता है। –

1

ये विधियां इंटर-थ्रेड संचार को लागू करने के लिए हैं।

this article on the subject देखें। उन तरीकों, उस लेख से लिया के लिए

नियम:

  • प्रतीक्षा() बुला धागा बताता है पर नजर रखने के हार और जब तक कुछ अन्य धागा ही मॉनिटर प्रवेश करती है और कॉल को सूचित सोने के लिए जाने के लिए() ।
  • सूचित करें() उसी ऑब्जेक्ट पर प्रतीक्षा() नामक पहले थ्रेड को जगाता है।
  • सूचित करें सभी() एक ही ऑब्जेक्ट पर प्रतीक्षा() नामक सभी थ्रेड को जगाता है। सर्वोच्च प्राथमिकता धागा पहले चलाएगा।

आशा इस मदद करता है ...

+3

वे इंटर- * प्रक्रिया * संचार नहीं करते हैं - वे इंटर- * थ्रेड * समन्वय करते हैं। सुधार के लिए –

+0

thx। – KB22

+0

वहां। सही किया। –

2

जावा में सभी ऑब्जेक्ट्स उनके साथ जुड़े मॉनीटर हैं। सिंक्रनाइज़ेशन प्राइमेटिव्स बहुत अधिक बहु-थ्रेडेड कोड में उपयोगी होते हैं, और इसके द्वारा अलग-अलग "मॉनीटर" ऑब्जेक्ट्स के बजाय आप जिस ऑब्जेक्ट को एक्सेस कर रहे हैं उस पर सिंक्रनाइज़ करने के लिए यह बहुत ही अच्छा है।

जावा आवश्यक वस्तुओं के साथ जुड़े मॉनीटर आवंटित कर सकता है - जैसा कि .NET करता है - और किसी भी मामले में लॉक आवंटित करने के लिए वास्तविक ओवरहेड (लेकिन उपयोग नहीं कर रहा) काफी छोटा होगा।

संक्षेप में: ऑब्जेक्ट्स को उनके थ्रेड सुरक्षा समर्थन बिट्स के साथ स्टोर करना वास्तव में सुविधाजनक है, और बहुत कम प्रदर्शन प्रभाव है।

+0

मुझे नहीं लगता कि यह वास्तव में सुविधाजनक है - सर्वोत्तम अभ्यास अनुशंसा करता है कि आप अपनी कक्षा के बाहर उन्हें उजागर न करके ताले को समाहित न करें जब तक आपको वैसे भी आवश्यकता न हो (उदा। "इस" या "Foo.class" को लॉक न करें)। यह अधिक सुरुचिपूर्ण * और * थोड़ा अधिक भंडारण-कुशल होगा न कि प्रत्येक वर्ग के साथ संभावित रूप से जुड़े मॉनीटर को। –

+0

एहह ... यदि आप नियमित रूप से कक्षा से फ़ील्ड का पर्दाफाश कर रहे हैं तो आपके पास लॉकिंग दक्षता से अलग समस्याएं हैं। मैं सहमत हूं कि आप लॉक ऑब्जेक्ट्स को स्पष्ट रूप से घोषित करके कुछ मेमोरी सहेज सकते हैं, लेकिन यह आकार (शून्य *) या आकार (int) प्रति-ऑब्जेक्ट (आलसी प्रारंभिक मानते हुए) के क्रम में होना चाहिए; यदि आप __that__ चिंतित हैं तो शायद आपको JVM के रूप में बड़े रनटाइम में लिंक नहीं करना चाहिए। –

12

क्यों इन इतना मौलिक हैं हर वस्तु उन्हें करने के लिए है और यह है कि उनमें (संभवतः कुछ राज्य में उन्हें संग्रहीत किया जाता है) होने में एक प्रदर्शन हिट?

टीएल; डॉ: वे थ्रेड-सुरक्षा विधियां हैं और उनके मूल्य के सापेक्ष छोटी लागतें हैं।

मौलिक वास्तविकताओं these methods समर्थन कर रहे हैं कि है कि:

  1. जावा हमेशा मल्टी-थ्रेडेड है। उदाहरण: jconsole या jvisualvm का उपयोग करके किसी प्रक्रिया द्वारा प्रयुक्त थ्रेड की सूची देखें।
  2. सुधार "प्रदर्शन" से अधिक महत्वपूर्ण है। जब मैं परियोजनाओं (कई साल पहले) ग्रेडिंग कर रहा था, तो मुझे समझाना पड़ता था कि "गलत जवाब पर वास्तव में तेजी से अभी भी गलत है।"

मूल रूप से, ये विधियां सिंक्रनाइज़ेशन में उपयोग किए गए प्रति-ऑब्जेक्ट मॉनीटर प्रबंधित करने के लिए कुछ हुक प्रदान करती हैं। विशेष रूप से, यदि मेरे पास synchronized(objectWithMonitor) किसी विशेष विधि में है, तो मैं उस मॉनीटर को उत्पन्न करने के लिए objectWithMonitor.wait() का उपयोग कर सकता हूं (उदाहरण के लिए, यदि मुझे आगे बढ़ने से पहले गणना पूर्ण करने के लिए किसी अन्य विधि की आवश्यकता है)। उस स्थिति में, वह उस अन्य विधि को अनुमति देगा जो उस मॉनिटर को आगे बढ़ने के लिए अवरुद्ध कर रहा था।

दूसरी ओर, मैं objectWithMonitor.notifyAll() का उपयोग कर सकता हूं ताकि मॉनिटर के लिए इंतजार कर रहे थ्रेड को पता चल जाए कि मैं जल्द ही मॉनिटर को छोड़ दूंगा। हालांकि, जब तक मैं सिंक्रनाइज़ किए गए ब्लॉक को छोड़ नहीं देता तब तक वे वास्तव में आगे नहीं बढ़ सकते हैं।

विशिष्ट उदाहरण (जैसे, डबल्स की लंबी सूची) जहां चिंता हो सकता है एक प्रदर्शन या स्मृति निगरानी तंत्र पर चोट नहीं है कि के संबंध में

, यहाँ कुछ अंक है कि आप की संभावना पर विचार करना चाहिए रहे हैं:

  1. पहले , इसे साबित करो। यदि आपको लगता है कि मूल जावा तंत्र जैसे बहु-थ्रेडेड शुद्धता से कोई बड़ा प्रभाव पड़ता है, तो आपके अंतर्ज्ञान गलत होने का एक शानदार मौका है। पहले प्रभाव को मापें। यदि यह गंभीर है और आप जानते हैं कि आपको कभी भी डबल डबल पर सिंक्रनाइज़ करने की आवश्यकता नहीं होगी, इसके बजाय युगल का उपयोग करने पर विचार करें।
  2. यदि आप निश्चित नहीं हैं कि आप, आपके सहकर्मी, भावी रखरखाव कोडर (जो स्वयं एक वर्ष बाद हो सकता है) इत्यादि।, कभी भी कभी भी आपके डेटा तक सीमित पहुंच की एक अच्छी ग्रैन्युलरिटी की आवश्यकता नहीं होगी, इन मॉनीटरों को दूर करने का एक शानदार मौका केवल आपके कोड को कम लचीला और बनाए रखने योग्य बनाएगा।

प्रति-वस्तु बनाम स्पष्ट नजर रखने वस्तुओं पर सवाल के जवाब में पालन-अप:

लघु जवाब: @JonSkeet: हाँ, पर नज़र रखता है को हटाने समस्या पैदा होगा: यह बन जाएगा टकराव। Object में उन मॉनीटर को रखने से हमें याद दिलाता है कि यह हमेशा एक बहुप्रचारित प्रणाली है।

बिल्ट-इन ऑब्जेक्ट मॉनीटर परिष्कृत नहीं हैं लेकिन वे हैं: समझाने में आसान; एक अनुमानित फैशन में काम करते हैं; और उनके उद्देश्य में स्पष्ट हैं। synchronized(this) इरादे का एक स्पष्ट बयान है। यदि हम नौसिखिया कोडर को विशेष रूप से समवर्ती पैकेज का उपयोग करने के लिए मजबूर करते हैं, तो हम घर्षण पेश करते हैं। उस पैकेज में क्या है? एक सैमफोर क्या है? कांटा-में शामिल होने?

एक नौसिखिया कोडर ऑब्जेक्ट मॉनीटर का उपयोग सभ्य मॉडल-व्यू-कंट्रोलर कोड लिखने के लिए कर सकता है। synchronized, wait और notifyAll का उपयोग निष्पक्ष (सरल, सुलभ लेकिन शायद रक्तस्राव-किनारे प्रदर्शन के भाव में) थ्रेड-सुरक्षा को लागू करने के लिए किया जा सकता है। कैननिकल उदाहरण इन डबल्स में से एक होगा (ओपी द्वारा प्रस्तुत) जिसमें एक थ्रेड एक मूल्य निर्धारित कर सकता है जबकि एडब्ल्यूटी थ्रेड को इसे जेएलएबल पर रखने का मूल्य मिलता है। उस स्थिति में, बाहरी मॉनीटर रखने के लिए एक स्पष्ट अतिरिक्त ऑब्जेक्ट बनाने का कोई अच्छा कारण नहीं है।

जटिलता के थोड़ा उच्च स्तर पर, ये वही विधियां बाह्य निगरानी विधि के रूप में उपयोगी होती हैं। उपर्युक्त उदाहरण में, मैंने स्पष्ट रूप से ऐसा किया (ऊपर ऑब्जेक्ट विथ मॉनिटर टुकड़े देखें)। फिर, ये विधियां अपेक्षाकृत सरल थ्रेड सुरक्षा को एक साथ रखने के लिए वास्तव में आसान हैं।

यदि आप और भी परिष्कृत होना चाहते हैं, तो मुझे लगता है कि आपको Java Concurrency In Practice पढ़ने के बारे में गंभीरता से सोचना चाहिए (यदि आपने पहले से नहीं किया है)। लॉक पढ़ें और लिखना बहुत अधिक जटिलता जोड़ने के बिना बहुत शक्तिशाली हैं।

पंचलाइन: बुनियादी सिंक्रनाइज़ेशन विधियों का उपयोग करके, आप थ्रेड-सुरक्षा के साथ आधुनिक बहु-कोर प्रोसेसर द्वारा सक्षम प्रदर्शन के एक बड़े हिस्से का फायदा उठा सकते हैं और बिना किसी ओवरहेड के।

+0

+1 "पहले, इसे साबित करें।" :) –

+1

@Aaron Digulla, धन्यवाद - व्यक्तिगत रूप से, मुझे लगता है कि किसी भी प्रदर्शन तर्क में पहली वाक्य होना चाहिए। –

+1

जबकि मैं यहां सभी सलाह से सहमत हूं, मुझे कार्यक्षमता के मौलिक रूप से महत्वपूर्ण बिट्स होने के बीच कोई संबंध नहीं दिख रहा है, और वे प्रत्येक वस्तु * के लिए मौलिक * हैं। दूसरे शब्दों में, यदि आप मॉनिटर के लिए एक अलग ऑब्जेक्ट का उपयोग करना चाहते हैं, तो क्या इसका कोई जवाब काम नहीं करेगा? –

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