समवर्ती संग्रह एपीआई, जावा संग्रह एपीआई के अलावा, संग्रह एपीआई का एक सेट है जो विशेष रूप से सिंक्रनाइज़ मल्टीथ्रेडेड एक्सेस के लिए डिज़ाइन और अनुकूलित किया गया है। वे java.util.concurrent . के अंतर्गत समूहीकृत हैं पैकेट। यह लेख एक उपयुक्त उदाहरण परिदृश्य का उपयोग करके एक सिंहावलोकन प्रदान करता है और इसके उपयोग का परिचय देता है।
एक सिंहावलोकन
जावा ने अपनी स्थापना से ही मल्टीथ्रेडिंग और कंसीडर का समर्थन किया है। थ्रेड्स या तो रननेबल . को लागू करके बनाए जाते हैं इंटरफ़ेस या थ्रेड का विस्तार करना कक्षा। सिंक्रनाइज़ेशन सिंक्रनाइज़ेशन . नामक कीवर्ड द्वारा प्राप्त किया जाता है . जावा थ्रेड्स के बीच संचार के लिए तंत्र भी प्रदान करता है। यह सूचित करें () . की मदद से हासिल किया जाता है और प्रतीक्षा करें () तरीके, जो ऑब्जेक्ट . का हिस्सा हैं कक्षा। हालांकि ये अभिनव मल्टीथ्रेडिंग तकनीक जावा की कुछ उत्कृष्ट विशेषताओं का हिस्सा हैं, लेकिन वे एक प्रोग्रामर की आवश्यकता प्रदान करने में कुछ हद तक कम हो जाते हैं, जिसके लिए बॉक्स से बाहर गहन मल्टीथ्रेडिंग क्षमता की आवश्यकता होती है। ऐसा इसलिए है क्योंकि एक समवर्ती कार्यक्रम को केवल धागे बनाने और कुछ प्राथमिक जोड़तोड़ करने में सक्षम होने की आवश्यकता होती है। इसके लिए कई उच्च-स्तरीय सुविधाओं की आवश्यकता होती है, जैसे कि थ्रेड पूल, निष्पादन प्रबंधक, सेमाफोर, इत्यादि।
मौजूदा संग्रह ढांचा
जावा में पहले से ही एक पूर्ण विकसित संग्रह ढांचा है। संग्रह वे जो करते हैं उसमें बहुत अच्छे हैं और जावा थ्रेड अनुप्रयोगों में भी इसका उपयोग किया जा सकता है। साथ ही, एक कीवर्ड भी है, जिसे सिंक्रनाइज़ किया गया . कहा जाता है , उन्हें धागा सुरक्षित बनाने के लिए। हालांकि सतही तौर पर ऐसा लग सकता है कि वे मल्टीथ्रेडिंग में उपयोग किए जाने के लिए अच्छे हैं, जिस तरह से थ्रेड सुरक्षा हासिल की जाती है, वह इसके समवर्ती कार्यान्वयन में मुख्य बाधा है। स्पष्ट तुल्यकालन के अलावा, वे शुरू से ही समवर्ती कार्यान्वयन के प्रतिमान के तहत तैयार नहीं किए गए हैं। संग्रह की स्थिति तक सभी पहुंच को क्रमबद्ध करके इन संग्रहों का सिंक्रनाइज़ेशन प्राप्त किया जाता है। इसका मतलब यह है कि, हालांकि हमारे पास कुछ संगामिति हो सकती है, अंतर्निहित क्रमबद्ध प्रसंस्करण के कारण यह एक सिद्धांत पर काम करता है जो वास्तव में विपरीत है। क्रमांकन प्रदर्शन पर भारी पड़ता है, खासकर जब एकाधिक थ्रेड संग्रह-व्यापी लॉक के लिए प्रतिस्पर्धा करते हैं।
नए संग्रह API
समवर्ती संग्रह एपीआई संस्करण 5 से जावा के अतिरिक्त हैं और java.util.concurrent नामक पैकेज का एक हिस्सा हैं। . वे मौजूदा संग्रह एपीआई में सुधार कर रहे हैं और कई थ्रेड्स से समवर्ती पहुंच के लिए डिज़ाइन किए गए हैं। उदाहरण के लिए, ConcurrentHashMap वास्तव में वह वर्ग है जिसकी हमें आवश्यकता होती है जब हम एक सिंक्रनाइज़ हैश-आधारित मानचित्र . का उपयोग करना चाहते हैं कार्यान्वयन। इसी तरह, यदि हम एक ट्रैवर्सल-प्रमुख, थ्रेड-सुरक्षित सूची चाहते हैं , हम वास्तव में CopyOnWriterArrayList . का उपयोग कर सकते हैं कक्षा। नया समवर्ती मानचित्र इंटरफ़ेस एक ही विधि के तहत कई यौगिक क्रियाएँ प्रदान करता है, जैसे कि putIfPresent , computeIfPresent , प्रतिस्थापित करें , मर्ज , और इसी तरह। ऐसे कई वर्ग हैं जो नए समवर्ती संग्रह ढांचे के भीतर हैं। कुछ नाम रखने के लिए:ArrayBlockingQueue , ConcurrentLinkedDeque , ConcurrentLinkedQueue , ConcurrentSkipListMap , ConcurrentSkipListSet , CopyOnWriteArraySet , DelayQueue , LinkedBlockingDeque , LinkedBlockingQueue , LinkedTransferQueue , प्राथमिकता अवरोधन कतार , तुल्यकालिक कतार , और अन्य।
कतार
संग्रह प्रकार, जैसे कतार और ब्लॉकिंग कतार , किसी तत्व को अस्थायी रूप से रखने के लिए इस्तेमाल किया जा सकता है, प्रसंस्करण के लिए फीफो तरीके से पुनर्प्राप्ति की प्रतीक्षा कर रहा है। ConcurrentLinkQueue दूसरी ओर, एक पारंपरिक फीफो कतार है जिसे लिंक्ड नोड्स के आधार पर एक असीमित, थ्रेड-सुरक्षित कतार के रूप में कार्यान्वित किया जाता है। प्राथमिकता अवरोधन कतार एक अनबाउंड ब्लॉकिंग क्यू है जो गैर-समवर्ती PriorityQueue के समान ऑर्डरिंग मानदंडों का उपयोग करती है और अवरुद्ध पुनर्प्राप्ति कार्यों की आपूर्ति करता है।
मानचित्र
पुराने संग्रह वर्गों में जब सिंक्रनाइज़ेशन लागू किया जाता है, तो यह प्रत्येक ऑपरेशन की अवधि के लिए ताले रखता है। कुछ ऑपरेशन हैं, जैसे कि प्राप्त करें हैश मैप . की विधि या शामिल हैं सूची . की विधि , जिसमें लागू होने पर दृश्य के पीछे जटिल गणना शामिल होती है। उदाहरण के लिए, किसी सूची में एक विशिष्ट तत्व को खोजने के लिए, यह स्वचालित रूप से बराबर . को आमंत्रित करता है तरीका। सूची में प्रत्येक तत्व की तुलना करने के लिए इस पद्धति के लिए निश्चित गणना की आवश्यकता होती है; कार्य को पूरा करने में लंबा समय लग सकता है। हैश-आधारित संग्रह में यह बदतर है। यदि हैश मैप में तत्वों को असमान रूप से वितरित किया जाता है, तो एक लंबी सूची को पार करने और बराबर कॉल करने में बहुत लंबा समय लग सकता है। यह एक समस्या है क्योंकि यह एप्लिकेशन के समग्र प्रदर्शन को प्रभावित कर सकती है।
हैश मैप के विपरीत , ConcurrentHashMap पूरी तरह से एक अलग रणनीति का उपयोग करता है। प्रत्येक सिंक्रनाइज़ विधि के लिए एक सामान्य लॉक प्रदान करने के बजाय, यह लॉक स्ट्रिपिंग . नामक तकनीक का उपयोग करता है . यह समवर्ती और मापनीयता दोनों के लिए एक बेहतर समाधान है। लॉक स्ट्रिपिंग अलग बाल्टी के लिए अलग ताले का उपयोग करता है। नतीजतन, थ्रेड विवाद को अंतर्निहित डेटा संरचना से अलग कर दिया जाता है और इसके बजाय बाल्टी पर लगाया जाता है। उदाहरण के लिए, ConcurrentHashMap का कार्यान्वयन 16 तालों की एक सरणी का उपयोग करता है—जिनमें से प्रत्येक हैश बकेट के 1/16 को गार्ड करता है; बाल्टी एन को लॉक एन मोड 16 द्वारा संरक्षित किया जाता है ... यह किसी भी लॉक की मांग को लगभग 16 के कारक से कम कर देता है। यह इस तकनीक के कारण है कि ConcurrentHashMap डिफ़ॉल्ट रूप से कम से कम 16 समवर्ती लेखकों का समर्थन करता है और अधिक मांग पर समायोजित किया जा सकता है।
CopyOnWriterArrayList
यह समकालिक सूची . का एक अच्छा विकल्प है और आपको पुनरावृत्ति के दौरान लॉकिंग तंत्र लागू करने की आवश्यकता नहीं है। पुनरावर्तक पुनरावृत्ति की शुरुआत में बैकिंग सरणी के संदर्भ को बनाए रखता है और इसे नहीं बदलता है। इसलिए, सरणी की सामग्री प्राप्त करने के लिए इसे एक संक्षिप्त सिंक्रनाइज़ेशन की आवश्यकता होती है। एकाधिक धागे एक दूसरे के साथ हस्तक्षेप किए बिना संग्रह तक पहुंच सकते हैं। यहां तक कि कई धागों से किए गए संशोधन पर भी विवाद नहीं होता है। इस सरणी सूची का एक सेट समकक्ष है, जिसे CopyOnWriterSet . कहा जाता है , जिसका उपयोग सिंक्रनाइज़ किए गए सेट . को बदलने के लिए किया जा सकता है समवर्ती आवश्यकता पर।
एक त्वरित उदाहरण
समवर्ती संग्रह में कई वर्ग हैं। पुराने संग्रह ढांचे से परिचित किसी भी व्यक्ति के लिए उनका उपयोग उतना मुश्किल नहीं है। पूर्णता के लिए, जावा प्रोग्रामिंग में इसके उपयोग की एक झलक प्रदान करने के लिए यहां एक उदाहरण दिया गया है।
package org.mano.example; import java.util.Random; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; public class ProducerConsumerDemo { static BlockingQueue<Integer> queue = new LinkedBlockingQueue<>(5); public static void main(String[] args) throws InterruptedException { int noOfProducers = 7; int noOfConsumers = 9; for (inti = 0; i < noOfProducers; i++) { new Thread(new Producer(), "PRODUCER").start(); } for (int i = 0; i < noOfConsumers; i++) { new Thread(new Consumer(), "CONSUMER").start(); } System.exit(0); } static class Producer implements Runnable { Random random = new Random(); public void run() { try { int num = random.nextInt(100); queue.put(num); System.out.println("Produced: " + num + " Queue size : "+ queue.size()); Thread.sleep(100); } catch (InterruptedException ex) { System.out.println("Producer is interrupted."); } } } static class Consumer implements Runnable { public void run() { try { System.out.println("Consumed: " + queue.take() + " Queue size : "+ queue.size()); Thread.sleep(100); } catch (InterruptedException ex) { System.out.println("Consumer is interrupted."); } } } }
निष्कर्ष
शायद समवर्ती संग्रह वर्गों का उपयोग करने का सबसे बड़ा लाभ उनकी मापनीयता और कम जोखिम है। जावा के समवर्ती संग्रह एपीआई कई प्रकार की कक्षाएं प्रदान करते हैं जिन्हें विशेष रूप से समवर्ती संचालन से निपटने के लिए डिज़ाइन किया गया है। ये वर्ग जावा संग्रह ढांचे के विकल्प हैं और समवर्ती के अतिरिक्त समर्थन को छोड़कर समान कार्यक्षमता प्रदान करते हैं। इसलिए, प्रोग्रामर के लिए सीखने की अवस्था जो पहले से ही जावा कलेक्शन फ्रेमवर्क के बारे में जानती है, लगभग सपाट है। कक्षाएं java.util.concurrent . पैकेज में परिभाषित हैं . यहां, मैंने शुरू करने के लिए एक सिंहावलोकन देने की कोशिश की है और जहां भी आवश्यक हो, संग्रह एपीआई का उपयोग करें।
संदर्भ
- जावा एपीआई दस्तावेज़ीकरण
- गोएट्ज़, ब्रायन और टिम पीयरल्स। Java Concurrency in practice . पियर्सन, 2013.