2015-09-25 18 views
14

मुझे संदेह है कि जावा भाषा में, हमें कुछ शर्त होने से पहले, लॉक पकड़ने की आवश्यकता है।लॉक स्थिति का इंतजार क्यों लॉक

उदाहरण के लिए, पूर्णांक जावा मॉनिटर ताला:

synchronized(lock){ 
    System.out.println("before lock ..."); 
    lock.wait(); 
    System.out.println("after lock ..."); 
} 

या cucurrent utils।

Lock lock = new ReentrantLock(); 
Condition cond = lock.newCondition(); 

lock.lock(); 
try{ 
    System.out.println("before condition ..."); 
    cond.await(); 
    System.out.println("after condition ..."); 
}catch(Exception e){ 
    e.printStackTrace(); 
}finally{ 
    lock.unlock(); 
} 

तो, हम लॉक पकड़ने के बिना क्यों इंतजार नहीं कर सकते हैं?

यदि जावा की वजह से, अन्य भाषा काम अलग-अलग हैं?

मुझे आशा है कि आप डिज़ाइन के बाद कारण बता सकते हैं, न केवल जावा-एसपीईसी परिभाषा के लिए।

+2

जावा वर्चुअल मशीन के संदर्भ में चलता है, और वर्चुअल मशीन का व्यवहार निर्दिष्ट होता है। –

+0

तो, यह SPEC की वजह से है? – Chinaxing

+2

बेशक यह विनिर्देश के कारण है। अजीब सवाल। – EJP

उत्तर

10

कल्पना कीजिए कि आपके पास ऐसा कुछ है जिसके लिए थ्रेड की प्रतीक्षा करनी पड़ सकती है। हो सकता है कि आपके पास कतार हो और थ्रेड को कतार पर कुछ न होने तक प्रतीक्षा करने की आवश्यकता हो ताकि वह इसे संसाधित कर सके। कतार थ्रेड-सुरक्षित होना चाहिए, इसलिए इसे लॉक द्वारा संरक्षित किया जाना चाहिए। आप निम्नलिखित कोड लिख सकते हैं:

  1. लॉक प्राप्त करें।
  2. जांचें कि कतार खाली है या नहीं।
  3. यदि कतार खाली है, तो कतार पर कुछ रखने के लिए प्रतीक्षा करें।

ओह, यह काम नहीं करेगा। हम कतार पर ताला पकड़ते हैं तो एक और धागा इस पर कुछ कैसे रख सकता है? आइए पुनः प्रयास करें:

  1. लॉक प्राप्त करें।
  2. जांचें कि कतार खाली है या नहीं।
  3. यदि कतार खाली है, तो लॉक जारी करें और कतार पर कुछ रखने के लिए प्रतीक्षा करें।

ओह, अब हमें अभी भी एक समस्या है। क्या होगा यदि हम लॉक जारी करने के बाद, लेकिन कतार पर कुछ रखने के लिए प्रतीक्षा करने से पहले, कतार पर कुछ रखा जाता है? उस स्थिति में, हम पहले से ही कुछ ऐसा इंतजार करेंगे।

इस सटीक समस्या को हल करने के लिए कंडीशन चर मौजूद हैं। उनके पास एक परमाणु "अनलॉक और प्रतीक्षा" ऑपरेशन है जो इस विंडो को बंद करता है।

तो प्रतीक्षा करें लॉक को पकड़ना चाहिए क्योंकि अन्यथा यह सुनिश्चित करने का कोई तरीका नहीं होगा कि आप पहले से ही कुछ ऐसा इंतजार नहीं कर रहे थे। अपने इंतजार के साथ रेसिंग से दूसरे थ्रेड को रोकने के लिए आपको लॉक रखना होगा।

+0

जावा, हालत या ऑब्जेक्ट में। केवल सूचित या सिग्नल के बाद जागृत रहें। तो, आपकी व्याख्या सही है। मुझे लगता है कि अगर हम इस तरह की स्थिति को अर्थपूर्ण बना सकते हैं: प्रतीक्षा करें/प्रतीक्षा करें, इसके जागने की बिट (जिसे सूचित/सिग्नल द्वारा सेट किया गया था) की जांच करें, यदि यह सच है, तो प्रतीक्षा करें/प्रतीक्षा करें (प्रतीक्षा रखने के बजाए)। और अधिसूचना/सिग्नल थ्रेड के लिए, सूचित करें जब सिग्नल/सिग्नल दें, तो हालत को जागृत करें, जिसका मतलब है कि स्थिति संतुष्ट है। यदि इस तरह का डिज़ाइन है, तो लॉक अधिग्रहण की आवश्यकता नहीं है? – Chinaxing

+1

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

0

सरल उत्तर इसलिए है क्योंकि अन्यथा आपको IllegalMonitorStateException मिलेगा जो ऑब्जेक्ट.वाइट जावाडोक में निर्दिष्ट है। आंतरिक रूप से, जावा में सिंक्रनाइज़ेशन अंतर्निहित ओएस मैकेनिज्म का उपयोग करता है। तो यह केवल जावा नहीं है।

+0

हाँ, लेकिन ओपी जानना चाहता है _why_ आपको IllegalMonitorStateException मिलता है। –

1

Condition के लिए दस्तावेज़ देखें।

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

1

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

8

अच्छा, हम किसके लिए प्रतीक्षा कर रहे हैं? हम एक शर्त को सच होने की प्रतीक्षा कर रहे हैं। एक और धागा स्थिति को सच बना देगा, फिर प्रतीक्षा धागे को सूचित करें।

प्रतीक्षा करने से पहले, हमें यह जांचना होगा कि स्थिति गलत है; यह चेक और प्रतीक्षा परमाणु होना चाहिए, यानी एक ही लॉक के नीचे होना चाहिए। अन्यथा, अगर हम प्रतीक्षा करते हैं तो प्रतीक्षा में प्रवेश करते समय, हम कभी भी जागृत नहीं होंगे।

इसलिए यह आवश्यक है कि लॉक पहले wait()

synchronized(lock) 
{ 
    if(!condition) 
     lock.wait(); 

तो wait() स्वचालित रूप से कॉल करने से पहले हासिल कर ली है और चुपचाप ताला प्राप्त कर लेता है, एक बहुत कीड़े की चल पाता जाना होगा।


wait() से Wakeup करने पर हमने पाया हालत फिर से जांच करना चाहिए - (- नकली Wakeup कारणों में से बहुत सारे के लिए; टाइमआउट, रुकावट, कई वेटर, कई की स्थिति) कोई गारंटी नहीं कि हालत यहाँ सच बन जाना चाहिए वहाँ

synchronized(lock) 
{ 
    if(!condition) 
     lock.wait(); 
    if(!condition) // check again 
     ... 

आमतौर पर, यदि स्थिति अभी भी झूठी है, तो हम फिर से प्रतीक्षा करेंगे। इसलिए सामान्य पैटर्न

while(!condition) 
     lock.wait(); 

लेकिन ऐसे मामले भी हैं जहां हम फिर से इंतजार नहीं करना चाहते हैं।


क्या कभी कानूनी उपयोग के मामले हो सकते हैं जहां नग्न प्रतीक्षा/अधिसूचना समझ में आती है?

synchronized(lock){ lock.wait(); } 

निश्चित; अच्छी तरह से परिभाषित व्यवहार के साथ, नग्न प्रतीक्षा/अधिसूचना के साथ एक आवेदन किया जा सकता है; तर्क दिया जा सकता है कि यह वांछित व्यवहार है; और यह उस व्यवहार के लिए सबसे अच्छा कार्यान्वयन है।

हालांकि, यह सामान्य उपयोग पैटर्न नहीं है, और इसके लिए एपीआई डिज़ाइन में इसके लिए कोई कारण नहीं है।

+0

ठीक है, यहां तक ​​कि "नग्न प्रतीक्षा" के साथ, हमें समस्या है कि 'प्रतीक्षा' केवल तभी वापस आएगी जब कोई अन्य धागा 'प्रतीक्षा' शुरू होने के बाद 'सूचित करें' * कहता है। लेकिन दोनों धागे एक ही वस्तु पर 'सिंक्रनाइज़' होने के बिना, एक ऑर्डरिंग रिलेशनशिप भी नहीं है। यह स्पष्ट रूप से ध्यान दिया जाना चाहिए कि न केवल इस शर्त की कोई गारंटी नहीं है कि स्थिति सच हो गई है, इस बात की कोई गारंटी नहीं है कि अधिसूचना और जागरूकता के बीच स्थिति फिर से झूठी नहीं हुई। – Holger

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