थ्रेड के बीच डेटा को आगे और आगे पास करने का एक आसान तरीका पैकेज java.util.concurrent
में स्थित इंटरफ़ेस BlockingQueue<E>
के कार्यान्वयन का उपयोग करना है।
add(E)
: इस इंटरफेस अलग व्यवहार के साथ संग्रह करने के लिए तत्वों को जोड़ने के तरीकों है यदि संभव हो तो कहते हैं, नहीं तो अपवाद
boolean offer(E)
फेंकता है: TRUE देता तत्व जोड़ दिया गया है, अन्यथा गलत
boolean offer(E, long, TimeUnit)
: तत्व जोड़ने की कोशिश करता है, निर्दिष्ट समय की प्रतीक्षा
put(E)
: जब तक तत्व जोड़ा नहीं जाता है तब तक कॉलिंग थ्रेड को अवरुद्ध करता है
यह भी समान व्यवहार के साथ तत्व पुनः प्राप्ति के लिए तरीकों को परिभाषित करता है ब्लॉक एक तत्व उपलब्ध
poll(long, TimeUnit)
वहाँ तक: एक तत्व को पुन: प्राप्त या रिटर्न शून्य
कार्यान्वयन मैं अक्सर उपयोग करता हूं: ArrayBlockingQueue
, LinkedBlockingQueue
और SynchronousQueue
।
पहला, ArrayBlockingQueue
, का एक निश्चित आकार है, जो उसके कन्स्ट्रक्टर को पास किए गए पैरामीटर द्वारा परिभाषित किया गया है।
दूसरा, LinkedBlockingQueue
, आकार का आकार है। यह हमेशा किसी भी तत्व को स्वीकार करेगा, यानी offer
तुरंत वापस आ जाएगा, add
कभी अपवाद नहीं फेंक देगा।
तीसरा, और मेरे लिए सबसे दिलचस्प एक, SynchronousQueue
, बिल्कुल एक पाइप है। आप इसे आकार 0 के साथ कतार के रूप में सोच सकते हैं। यह कभी भी तत्व नहीं रखेगा: यह कतार केवल तत्वों को स्वीकार करेगी यदि कुछ अन्य थ्रेड इसके तत्वों को पुनर्प्राप्त करने का प्रयास कर रहे हैं। इसके विपरीत, एक पुनर्प्राप्ति ऑपरेशन केवल एक तत्व लौटाएगा यदि कोई अन्य थ्रेड इसे धक्का देने का प्रयास कर रहा है।
होमवर्क संकेतबाहु के साथ विशेष रूप से किया तुल्यकालन की आवश्यकता को पूरा करने के लिए आपको वर्णन मैं SynchronousQueue के बारे में आप दे दी द्वारा प्रेरित हो सकता है, और काफी कुछ इसी तरह लिखें:
class Pipe<E> {
private E e;
private final Semaphore read = new Semaphore(0);
private final Semaphore write = new Semaphore(1);
public final void put(final E e) {
write.acquire();
this.e = e;
read.release();
}
public final E take() {
read.acquire();
E e = this.e;
write.release();
return e;
}
}
सूचना यह है कि कक्षा सिंक्रोनस्यूयूयू के बारे में वर्णित किए गए समान व्यवहार को प्रस्तुत करती है।
एक बार विधियों put(E)
को कहा जाता है कि यह लिखने सेमफोर प्राप्त करता है, जिसे खाली छोड़ दिया जाएगा, ताकि एक ही विधि के लिए एक और कॉल अपनी पहली पंक्ति पर अवरुद्ध हो। यह विधि तब पारित होने वाली वस्तु का संदर्भ संग्रहीत करती है, और पढ़ने सेमफोर जारी करती है। इस रिलीज से आगे बढ़ने के लिए take()
विधि को कॉल करने वाले किसी भी थ्रेड के लिए यह संभव हो जाएगा।
take()
विधि का पहला चरण तब, स्वाभाविक रूप से, पढ़ा सैमफोर प्राप्त करने के लिए, तत्व को पुनः प्राप्त करने के लिए किसी अन्य थ्रेड को अस्वीकार करने के लिए किया जाता है। तत्व को पुनर्प्राप्त करने के बाद और स्थानीय चर में रखा गया है (व्यायाम: क्या होगा यदि उस पंक्ति, ई ई = this.e को हटा दिया गया था?), विधि लिखने सेमफोर जारी करती है, ताकि विधि put(E)
हो किसी भी थ्रेड द्वारा फिर से बुलाया जाता है, और स्थानीय चर में जो बचाया गया है उसे लौटाता है।
एक महत्वपूर्ण टिप्पणी के रूप में, देख सकते हैं कि वस्तु पारित किया जा रहा करने के लिए संदर्भ एक निजी क्षेत्र में रखा जाता है, और तरीकों take()
और put(E)
दोनों अंतिम हैं। यह अत्यंत महत्वपूर्ण है, और अक्सर याद किया जाता है। यदि ये विधियां अंतिम नहीं थीं (या बदतर, फ़ील्ड निजी नहीं है), एक विरासत वर्ग take()
और put(E)
अनुबंध को तोड़ने के व्यवहार को बदलने में सक्षम होगा। अगर सिर्फ try/finally
के उपयोग को दिखाने के लिए चला जाता है कि
class Pipe<E> {
// ...
public final E take() {
try {
read.acquire();
return e;
} finally {
write.release();
}
}
}
यहाँ, इस उदाहरण के बिंदु:
अंत में, आप इस प्रकार try {} finally {}
का उपयोग करके take()
विधि में एक स्थानीय चर घोषित करने के लिए आवश्यकता से बचने के सकता है अनुभवहीन डेवलपर्स के बीच अनजान। जाहिर है, इस मामले में, कोई वास्तविक लाभ नहीं है।
ओह अरे, मैंने आपके लिए अपना होमवर्क पूरा कर लिया है। प्रतिशोध में - और आपके लिए सेमफोरस के बारे में अपने ज्ञान का परीक्षण करने के लिए -, आप BlockingQueue अनुबंध द्वारा परिभाषित कुछ अन्य विधियों को क्यों लागू नहीं करते हैं? उदाहरण के लिए, आप offer(E)
विधि और take(E, long, TimeUnit)
लागू कर सकते हैं!
शुभकामनाएं।
मुख्य संकेत मैं दे शब्द "पाइप" के साथ एक मानसिक ब्लॉक पाने के लिए नहीं किया गया है जाएगा। जानकारी के साथ 'बॉक्स' रखने के बारे में और सोचें, और जब आप इसे देखने के लिए बॉक्स में कुछ दिलचस्प करते हैं तो अन्य धागे को बताने के लिए बॉक्स पर एक पोस्ट नोट डाल दें। –