LinkedBlockingQueue vs ConcurrentLinkedQueue


112

मेरा प्रश्न पहले पूछे गए इस प्रश्न से संबंधित है । उन स्थितियों में जहां मैं निर्माता और उपभोक्ता धागे के बीच संचार के लिए एक कतार का उपयोग कर रहा हूं, लोग आमतौर पर उपयोग करने की सलाह देंगे LinkedBlockingQueueया ConcurrentLinkedQueue?

एक के बाद एक उपयोग करने के क्या फायदे / नुकसान हैं?

एक एपीआई परिप्रेक्ष्य से मुख्य अंतर मैं देख सकता हूं कि LinkedBlockingQueueवैकल्पिक रूप से बाध्य किया जा सकता है।

जवाबों:


110

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

ब्लॉकिंग क्यू के लिए डॉक्स से:

BlockingQueue कार्यान्वयन को मुख्य रूप से निर्माता-उपभोक्ता कतारों के लिए उपयोग करने के लिए डिज़ाइन किया गया है

मैं जानता हूं कि यह कड़ाई से नहीं कहा गया है कि केवल उत्पादक-उपभोक्ता कतारों के लिए अवरोधक कतारों का उपयोग किया जाना चाहिए, लेकिन फिर भी ...


4
धन्यवाद जॉन - मैंने उस पर ध्यान नहीं दिया था। तो आप कहाँ / क्यों समवर्ती लानत क्यू उपयोग करेंगे?
एडम्सकी

27
जब आपको बहुत सारे थ्रेड से कतार तक पहुंचने की आवश्यकता होती है, लेकिन आपको उस पर "प्रतीक्षा" करने की आवश्यकता नहीं है।
जॉन स्कीट

2
ConcurrentLinkedQueueभी उपयोगी है अगर आपका धागा कई कतारों की जाँच कर रहा है। उदाहरण के लिए, एक बहु-किरायेदार सर्वर में। अलगाव कारणों के लिए मान लें कि आप एक एकल अवरुद्ध कतार और एक किरायेदार भेदभाव का उपयोग नहीं करते हैं।
लेटरलफ्रैक्टल

आपका मामला तभी सही साबित होता है जब हम बंधी हुई कतार का उपयोग करते हैं , अनबाउंड कतार में take()और put()अतिरिक्त संसाधन (केवल सिंक्रनाइज़ेशन के अंतराल) से अधिक खपत करते हैं ConcurrentLinkedQueue । हालांकि यह निर्माता-उपभोक्ता परिदृश्यों के
अमरनाथ हरिश

@ Adamski IMO, ConcurrentLinkedQueue एक बहु थ्रेडेड वातावरण में उपयोग किया जाने वाला एक लिंकलिस्ट है। इसके लिए सबसे अच्छा सादृश्य समवर्ती HashMap और HashMap होगा।
निशित

69

यह प्रश्न एक बेहतर उत्तर का हकदार है।

जावा के गैर-अवरोधक लॉक-फ्री कतारों के लिए Maged M. Michael और Michael L. Scott द्वाराConcurrentLinkedQueue प्रसिद्ध एल्गोरिथम पर आधारित है ।

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

जावा ConcurrentLinkedQueueकेवल नॉन-ब्लॉकिंग नहीं है, लेकिन इसमें भयानक संपत्ति है कि निर्माता उपभोक्ता के साथ संघर्ष नहीं करता है। एक एकल निर्माता / एकल उपभोक्ता परिदृश्य (एसपीएससी) में, इसका वास्तव में मतलब है कि बोलने का कोई विवाद नहीं होगा। एक से अधिक निर्माता / एकल उपभोक्ता परिदृश्य में, उपभोक्ता उत्पादकों के साथ संघर्ष नहीं करेगा। जब कई निर्माता प्रयास करते हैं offer(), तो यह कतार विवाद होती है , लेकिन यह परिभाषा द्वारा संक्षिप्त है। यह मूल रूप से एक सामान्य उद्देश्य और कुशल गैर-अवरुद्ध कतार है।

जैसा कि यह नहीं किया जा रहा है BlockingQueue, ठीक है, कतार पर प्रतीक्षा करने के लिए एक धागा को अवरुद्ध करना समवर्ती प्रणालियों को डिजाइन करने का एक भयावह रूप से भयानक तरीका है। मत करो। यदि आप ConcurrentLinkedQueueकिसी उपभोक्ता / निर्माता परिदृश्य में उपयोग करने का तरीका नहीं जान सकते हैं, तो एक अच्छे अभिनेता ढांचे की तरह उच्च-स्तरीय अमूर्त में स्विच करें।


8
अपने अंतिम पैराग्राफ के अनुसार, आप यह क्यों कहते हैं कि कतार पर इंतजार करना समवर्ती प्रणालियों को डिजाइन करने का एक भयानक तरीका है? अगर हमारे पास टास्क्यू से 10 थ्रेड खाने वाले कार्यों के साथ एक थ्रेडग्रुप है, तो टास्कक्यू के 10 कार्यों से कम होने पर अवरुद्ध होने में क्या गलत है?
पचेरियर

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

1
@ एडमगेंट - अभिनेता के ढांचे में अवरोधक कतारों के आधार पर मेलबॉक्सों का कार्यान्वयन होता है, लेकिन यह मेरी राय में एक बग है, क्योंकि अवरुद्ध करना अतुल्यकालिक सीमाओं पर काम नहीं करता है और इस प्रकार केवल डेमो में काम करता है। मेरे लिए यह हताशा का एक स्रोत रहा है, उदाहरण के लिए, अक्का की अतिप्रवाह से निपटने की धारणा ब्लॉक करने के बजाय, संदेश छोड़ने के बजाय, संस्करण 2.4 तक है, जो कि अभी तक बाहर नहीं है। कहा कि मुझे विश्वास नहीं है कि ऐसे उपयोग-मामले हैं जिनके लिए अवरुद्ध कतारें श्रेष्ठ हो सकती हैं। आप दो चीजों का भी सामना कर रहे हैं जिन्हें जब्त नहीं किया जाना चाहिए। मैंने I / O को अवरुद्ध करने के बारे में नहीं कहा है।
अलेक्जेंड्रू नेडेल्क्यू

1
@AlexandruNedelcu, जबकि मैं आमतौर पर बैकस्पेस पर आपके साथ सहमत हूं, मुझे अभी तक ऊपर से नीचे तक "लॉक फ्री" सिस्टम देखना है। कहीं न कहीं एक टेक्नॉलॉजी स्टैक में है कि क्या इसके Node.js, Erlang, Golang, किसी प्रकार की प्रतीक्षा रणनीति का उपयोग कर रहे हैं, चाहे वह एक अवरोधक (ताले) हो या CAS अपने अवरोधन को कताई कर रहा हो और कुछ मामलों में एक पारंपरिक लॉक रणनीति तेज़ है। इसकी बहुत मुश्किल है क्योंकि इसमें स्थिरता की वजह से ताले नहीं हैं और यह विशेष रूप से अवरुद्ध io और अनुसूचियों के साथ महत्वपूर्ण है जो ~ निर्माता / उपभोक्ता हैं। ForkJoinPool कम चलने वाले कार्यों के साथ काम करता है और इसमें अभी भी CAS कताई ताले हैं।
एडम जेंट

1
@AlexandruNedelcu मुझे लगता है कि यदि आप मुझे दिखा सकते हैं कि आप कैसे एक समवर्ती (क्यूई बाउंडेड bw इसलिए मेरी कमजोर बैकप्रेशर तर्क नहीं है) प्रोड्यूसर / उपभोक्ता पैटर्न के लिए उपयोग कर सकते हैं जो शेड्यूलर और थ्रेडपूलिंग के लिए आवश्यक एक पैटर्न है जो मुझे लगता है कि में दे दूँगा और स्वीकार करता हूँ BlockingQueue का उपयोग कभी नहीं किया जाना चाहिए (और आप धोखा नहीं दे सकते हैं और कुछ और शिड्यूलिंग कर सकते हैं अर्थात् शेड्यूलिंग कर रहे हैं, क्योंकि यह एक प्रोड्यूसर / कंज्यूमर है)
एडम जेंट

33

LinkedBlockingQueueजब उपभोक्ता खाली होता है या कतार खाली या भरी होती है और संबंधित उपभोक्ता / निर्माता को सोने के लिए डाल दिया जाता है। लेकिन यह अवरोधक सुविधा एक लागत के साथ आती है: प्रत्येक पुट या टेक ऑपरेशन को उत्पादकों या उपभोक्ताओं (यदि बहुत से) के बीच में लॉक किया गया है, तो कई उत्पादकों / उपभोक्ताओं के साथ परिदृश्य में ऑपरेशन धीमा हो सकता है।

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

तो जो एक "बेहतर" है, वह उपभोक्ता थ्रेड्स की संख्या पर निर्भर करता है, जिस दर पर वे उपभोग / उत्पादन करते हैं, आदि प्रत्येक परिदृश्य पर एक बेंचमार्क की आवश्यकता होती है।

एक विशेष उपयोग मामला जहां ConcurrentLinkedQueueस्पष्ट रूप से बेहतर होता है, जब निर्माता पहले कुछ उत्पादन करते हैं और काम को कतार में रखकर अपना काम पूरा करते हैं और उसके बाद ही उपभोक्ता उपभोग करना शुरू करते हैं, यह जानते हुए कि कतार खाली होने पर उन्हें किया जाएगा। (यहां निर्माता-उपभोक्ता के बीच कोई सहमति नहीं है लेकिन केवल निर्माता-निर्माता और उपभोक्ता-उपभोक्ता के बीच है)


यहाँ एक संदेह है। जैसा कि आप उल्लेख उपभोक्ता इंतजार कर रहा है जब कतार खाली है..तो यह कब तक प्रतीक्षा करता है। इंतजार नहीं करने के लिए इसे कौन सूचित करेगा?
ब्रिनल

@brindal यह प्रतीक्षा करने का एकमात्र तरीका, कि मुझे पता है, एक लूप में है। यह एक महत्वपूर्ण समस्या है जिसके जवाब में यहाँ बहुत ध्यान नहीं दिया गया है। बस डेटा के इंतजार में एक लूप चलाने से प्रोसेसर समय का बहुत उपयोग होता है। आपको यह तब पता चलेगा जब आपके प्रशंसक खुलासा करना शुरू करेंगे। एकमात्र उपाय पाश में नींद डालना है। तो यह असंगत डेटा प्रवाह के साथ एक प्रणाली में एक समस्या है। शायद मैं अलेक्जेंड्रू नेलडेलु के जवाब को गलत समझता हूं, लेकिन एक ऑपरेटिंग सिस्टम ही एक समवर्ती प्रणाली है, अगर यह गैर-अवरुद्ध ईवेंट लूप से भरा हुआ है, तो यह बेहद अक्षम होगा।
orodbhen

ठीक है, लेकिन अगर unbounded blockingqueueइसका उपयोग किया जाता है तो यह कैस आधारित समवर्ती से बेहतर होगाConcurrentLinkedQueue
अमरनाथ हरिश

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

वास्तव में, मुझे "उपभोग / उत्पादन दर" वाले हिस्से में बहुत दिलचस्पी है, इसलिए यदि कोई दर बेहतर है, तो क्या बेहतर होगा?
workplaylifecycle

0

एक अन्य समाधान (जो अच्छी तरह से पैमाने पर नहीं है) मिलनसार चैनल है: java.util.concurrent सिंक्रोनस क्यू


0

यदि आपकी कतार गैर-विस्तार योग्य है और इसमें केवल एक निर्माता / उपभोक्ता धागा है। आप लॉकलेस कतार का उपयोग कर सकते हैं (आपको डेटा एक्सेस लॉक करने की आवश्यकता नहीं है)।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.