8

में अपनी खुद की अवरुद्ध कतार लागू करें मुझे पता है कि इस सवाल से कई बार पहले पूछा गया है और उत्तर दिया गया है, लेकिन मैं इंटरनेट के आसपास पाए गए उदाहरणों पर this या that एक पर एक चाल नहीं समझ पाया।जावा

इन समाधानों में से

दोनों get() तरीकों में में put() विधि और इसके विपरीत notifyAll इंतजार कर रहे धागे को अवरुद्ध कतार के सरणी/कतार/linkedlist के खालीपन लिए जाँच करें। दूसरे लिंक में comment इस स्थिति पर जोर देता है और उल्लेख करता है कि यह आवश्यक नहीं है।

तो सवाल यह है; क्यूई खाली है या नहीं, यह मेरे लिए थोड़ा अजीब लगता है सभी प्रतीक्षा धागे को सूचित करने के लिए पूर्ण। कोई विचार?

अग्रिम धन्यवाद।

+2

समस्या का एक हिस्सा समवर्ती कार्यक्रमों में 'प्रतीक्षा' और 'सूचित करें 'का उपयोग करने में कठिनाई से संबंधित समस्या का हिस्सा अधिक विस्तृत उदाहरण पा सकते हैं; जोशुआ ब्लोच को उद्धृत करने के लिए, वे समवर्ती प्रोग्रामिंग के निम्न स्तर (असेंबली भाषा) की तरह हैं। " वह 'NotifyAll' का उपयोग करने की वकालत करता है और प्रतीक्षा करते समय थ्रेड को हमेशा एक लूप के भीतर चेक करना चाहिए ताकि वे आवश्यकतानुसार प्रतीक्षा कर सकें। वास्तव में, आपको बस प्रतीक्षा/अधिसूचना का उपयोग नहीं करना चाहिए और इसके बजाय हमेशा जावा एसई 5 में प्रदान किए गए उच्च स्तरीय समवर्ती एपीआई का उपयोग करने की योजना बनाना चाहिए। धागे की बजाय और प्रतीक्षा/सूचित करें, कार्य और निष्पादकों के संदर्भ में समवर्ती ऐप्स डिज़ाइन करें। – scottb

+0

हाँ, मैं पूरी तरह से आपसे सहमत हूं, बूढ़े लेकिन उपहार: पहिया का पुन: आविष्कार करने की कोई आवश्यकता नहीं है। लेकिन बस सोचें कि हमें इस मामले के लिए प्रतीक्षा और अधिसूचना का उपयोग करने की आवश्यकता है। मुझे पता है कि प्रतीक्षा() को लूप के भीतर इस्तेमाल किया जाना चाहिए, सभी javadocs (नकली wakeups) में समझाया गया है: http://docs.oracle.com/javase/6/docs/api/java/lang/Object.html#wait (लंबा)। लेकिन अधिसूचनाओं के लिए उन शर्तों के बारे में हैक क्या है? यही वह बिंदु है जिसे मैं नहीं मिला। – tugcem

+0

देखें [यहां] (http://fuseyism.com/classpath/doc/java/util/concurrent/LinkedBlockingQueue-source.html) - वे 'पुनर्वित्त लॉक' और 'कंडीशन' का उपयोग करते हैं, 'प्रतीक्षा नहीं'/'सूचित करें ' बिलकुल। – OldCurmudgeon

उत्तर

1

मुझे लगता है कि notifyAll() से पहले उस अतिरिक्त जांच को कोई नुकसान नहीं हुआ है।

एक बार जब आप कतार से कुछ प्राप्त करते हैं तो आप notifyAll() कर सकते हैं। सब कुछ अभी भी काम करेगा, और आपका कोड छोटा है। हालांकि, अगर कोई notifyAll() का आह्वान करने से पहले कोई संभावित रूप से प्रतीक्षा कर रहा है (कतार की सीमा को मारने पर जांच कर रहा है) तो कोई हानि जांच भी नहीं है। तर्क का यह अतिरिक्त टुकड़ा अनावश्यक notifyAll() आमंत्रण बचाता है।

यह सिर्फ एक छोटा और क्लीनर कोड चाहता है, या आप अपने कोड को अधिक कुशलता से चलाने के लिए चाहते हैं। (notifyAll() के कार्यान्वयन में नहीं देखा है। यदि कोई भी इंतजार नहीं कर रहा है तो यह एक सस्ता ऑपरेशन है, तो प्रदर्शन लाभ उस अतिरिक्त जांच के लिए स्पष्ट नहीं हो सकता है)

0

लेखक notifyAll() का उपयोग करने का कारण है सरल: उनके पास कोई सुराग नहीं था कि यह आवश्यक था या नहीं, इसलिए उन्होंने "सुरक्षित" विकल्प का फैसला किया।

उपरोक्त उदाहरण में यह प्रत्येक तत्व के लिए notify() पर कॉल करने के लिए पर्याप्त होगा, सभी परिस्थितियों में केवल एक ही थ्रेड प्रतीक्षा की जा सकती है।

यह अधिक स्पष्ट हो जाता है, यदि आपकी कतार में addAll(Collection<T> list) जैसे एक चरण में कई तत्व जोड़ने का विकल्प है, इस मामले में रिक्त सूची पर प्रतीक्षा करने वाले एक से अधिक धागे परोसा जा सकता है, सटीक होने के लिए: कई धागे तत्वों के रूप में जोड़ा गया है।

notifyAll() हालांकि विशेष एकल-तत्व मामले में अतिरिक्त ओवरहेड का कारण बनता है, क्योंकि कई धागे अनावश्यक रूप से जागृत होते हैं और इसलिए इस दौरान कतार पहुंच को अवरुद्ध करने के लिए फिर से सोना पड़ता है। इसलिए notifyAll()notify() के साथ इस विशेष मामले में गति में सुधार करेगा।

लेकिन तब नहीं इंतजार का उपयोग कर/सूचित करें और बिल्कुल भी सिंक्रनाइज़, लेकिन इसके बजाय समवर्ती पैकेज का उपयोग एक बहुत किसी भी स्मार्ट प्रतीक्षा की तुलना में अधिक से गति में वृद्धि होगी/कार्यान्वयन कभी करने के लिए मिल सकता है को सूचित करें।

12

मुझे पता है कि यह अब तक एक पुराना सवाल है, लेकिन प्रश्न और उत्तर पढ़ने के बाद मैं अपने स्वयं की मदद नहीं कर सका, मुझे आशा है कि आपको यह उपयोगी लगेगा।

पता चल सके कि कतार वास्तव में पूर्ण या खाली कुछ अन्य इंतजार कर रहे धागे को अधिसूचित करने से पहले, आप भूल रहे हैं जो है दोनों तरीकों put (T t) और T get() दोनों synchronized तरीके हैं, जिसका अर्थ है कि केवल एक धागा एक पर इन तरीकों में से एक में प्रवेश कर सकते है के बारे में समय, फिर भी यह उन्हें एक साथ काम करने से नहीं रोकेगा, इसलिए यदि कोई थ्रेड-ए put (T t) विधि दर्ज कर चुका है तो कोई अन्य थ्रेड-बी अभी भी दर्ज हो सकता है और थ्रेड से पहले T get() विधि में निर्देशों को निष्पादित करना प्रारंभ कर सकता है- put (T t) से बाहर निकला है, और इसलिए यह double-checking डिज़ाइन डेवलपर को थोड़ी अधिक सुरक्षित महसूस कर देगा क्योंकि आप नहीं जानते कि भविष्य में सीपीयू संदर्भ स्विचिंग अगर होगा या कब होगा। मैं इस दृष्टिकोण वहाँ double checking की आवश्यकता नहीं है का उपयोग करते हुए इस link

Condition isFullCondition; 
Condition isEmptyCondition; 
Lock lock; 

public BQueue() { 
    this(Integer.MAX_VALUE); 
} 

public BQueue(int limit) { 
    this.limit = limit; 
    lock = new ReentrantLock(); 
    isFullCondition = lock.newCondition(); 
    isEmptyCondition = lock.newCondition(); 
} 

public void put (T t) { 
    lock.lock(); 
    try { 
     while (isFull()) { 
      try { 
       isFullCondition.await(); 
      } catch (InterruptedException ex) {} 
     } 
     q.add(t); 
     isEmptyCondition.signalAll(); 
    } finally { 
     lock.unlock(); 
    } 
} 

public T get() { 
    T t = null; 
    lock.lock(); 
    try { 
     while (isEmpty()) { 
      try { 
       isEmptyCondition.await(); 
      } catch (InterruptedException ex) {} 
     } 
     t = q.poll(); 
     isFullCondition.signalAll(); 
    } finally { 
     lock.unlock(); 
    } 
    return t; 
} 

से स्रोत कोड संपादित कर लिया है //

,:

एक बेहतर और एक अधिक सिफारिश की दृष्टिकोण Reentrant Locks और Conditions उपयोग करने के लिए है क्योंकि lock ऑब्जेक्ट को दो विधियों के बीच साझा किया जाता है, जिसका अर्थ है कि केवल एक थ्रेड ए या बी सिंक्रनाइज़ किए गए तरीकों के विपरीत एक समय में इन तरीकों में से किसी एक को दर्ज कर सकता है जो विभिन्न मॉनीटर बनाता है, और केवल उन थ्रेड प्रतीक्षा कर रहे हैं क्योंकि कतार पूर्ण है, वहां और जगह है, और वही थ्रेड के लिए जाता है क्योंकि कतार खाली है, इससे बेहतर सीपीयू उपयोग होता है। आप स्रोत कोड here

+0

isfullConditon के बजाय, "isNotfullCondtion" इसे कार्यान्वयन के लिए और अधिक पठनीय +1 बना देगा –