एक का संशोधन Collection
करते हुए बार-बार दोहराना के माध्यम से उस Collection
का उपयोग कर एक Iterator
है की अनुमति नहीं के सबसे द्वारा Collection
कक्षाएं। जावा लाइब्रेरी Collection
इसे "समवर्ती संशोधन" के माध्यम से थोड़ी देर में संशोधित करने का प्रयास कहता है । यह दुर्भाग्य से एकमात्र संभव कारण बताता है कि एक साथ कई थ्रेड्स द्वारा संशोधन है, लेकिन ऐसा नहीं है। केवल एक धागे Collection
का उपयोग करके (उपयोग Collection.iterator()
या बढ़ाया for
लूप ) के लिए एक पुनरावृत्ति बनाना संभव है , पुनरावृत्ति शुरू करें (उपयोग Iterator.next()
, या समकक्ष रूप से बढ़ाया for
लूप के शरीर में प्रवेश ), संशोधित करेंCollection
, फिर पुनरावृत्ति जारी रखें।
प्रोग्रामर की मदद करने के लिए, उन वर्गों के कुछ कार्यान्वयन गलत समवर्ती संशोधन का पता लगाने का प्रयास करते हैं, और यदि वे इसका पता लगाते हैं तो उन्हें फेंक देते हैं । हालांकि, सभी समवर्ती संशोधनों का पता लगाने की गारंटी देना सामान्य और संभव नहीं है। इसलिए गलत का गलत इस्तेमाल हमेशा फेक नहीं होता ।Collection
ConcurrentModificationException
Collection
ConcurrentModificationException
का प्रलेखन ConcurrentModificationException
कहता है:
यह अपवाद उन विधियों द्वारा फेंका जा सकता है, जब किसी वस्तु के समवर्ती संशोधन का पता चला है, जब ऐसा संशोधन अनुमेय नहीं है ...
ध्यान दें कि यह अपवाद हमेशा इंगित नहीं करता है कि किसी वस्तु को एक अलग धागे द्वारा समवर्ती रूप से संशोधित किया गया है। यदि कोई एकल थ्रेड किसी विधि के अनुबंध का उल्लंघन करने वाली विधि इनवोकेशन का अनुक्रम जारी करता है, तो ऑब्जेक्ट इस अपवाद को फेंक सकता है ...
ध्यान दें कि असफल-तेज़ व्यवहार की गारंटी नहीं दी जा सकती क्योंकि यह आम तौर पर बोल रहा है, असम्बद्ध समवर्ती संशोधन की उपस्थिति में किसी भी हार्ड गारंटी को असंभव बनाना। असफल-फास्ट संचालन ConcurrentModificationException
एक सर्वोत्तम प्रयास के आधार पर फेंकते हैं।
ध्यान दें कि
के प्रलेखन HashSet
, HashMap
, TreeSet
और ArrayList
कक्षाओं इस कहते हैं:
पुनरावृत्तियाँ [इस श्रेणी से प्रत्यक्ष या अप्रत्यक्ष रूप से] विफल हो जाती हैं - यदि संग्रहकर्ता बनने के बाद किसी भी समय [संग्रह] संशोधित किया जाता है, तो किसी भी तरह से पुनरावृत्ति करने वाले के स्वयं के निष्कासन विधि के अलावा, Iterator
फेंकता है ConcurrentModificationException
। इस प्रकार, समवर्ती संशोधन के सामने, भविष्य में एक अनिर्धारित समय पर मनमाना, गैर-निर्धारक व्यवहार को जोखिम में डालने के बजाय, यह जल्दी और साफ-सुथरा हो जाता है।
ध्यान दें कि इट्रेटर के असफल-तेज़ व्यवहार की गारंटी नहीं दी जा सकती है क्योंकि यह आमतौर पर बोल रहा है, असम्बद्ध समवर्ती संशोधन की उपस्थिति में किसी भी हार्ड गारंटी को असंभव बनाता है। असफल-तेज़ पुनरावृत्तियों ConcurrentModificationException
को सर्वोत्तम प्रयास के आधार पर फेंकते हैं। इसलिए, एक प्रोग्राम लिखना गलत होगा जो इसके सही होने के लिए इस अपवाद पर निर्भर करता है: पुनरावृत्तियों के असफल-तेज़ व्यवहार का उपयोग केवल बग का पता लगाने के लिए किया जाना चाहिए ।
ध्यान दें कि व्यवहार "गारंटी नहीं दे सकता है" और केवल "सर्वश्रेष्ठ प्रयास के आधार पर" है।
Map
इंटरफ़ेस के कई तरीकों का प्रलेखन यह कहता है:
गैर-समवर्ती कार्यान्वयन को इस पद्धति को ओवरराइड करना चाहिए और सर्वोत्तम-प्रयास के आधार पर, ConcurrentModificationException
यदि यह पता चला है कि मैपिंग फ़ंक्शन कम्प्यूटेशन के दौरान इस मैप को संशोधित करता है। समवर्ती कार्यान्वयन इस पद्धति को ओवरराइड करना चाहिए और, सर्वोत्तम-प्रयास के आधार पर, IllegalStateException
यदि यह पता लगाया जाए कि मैपिंग फ़ंक्शन कम्प्यूटेशन के दौरान इस मैप को संशोधित करता है और परिणामस्वरूप कम्प्यूटेशन कभी पूरा नहीं होगा।
फिर से ध्यान दें कि पता लगाने के लिए केवल "सर्वश्रेष्ठ-प्रयास का आधार" आवश्यक है, और ConcurrentModificationException
स्पष्ट रूप से केवल गैर-समवर्ती (गैर-थ्रेड-सुरक्षित) वर्गों के लिए सुझाव दिया गया है।
डिबगिंग ConcurrentModificationException
इसलिए, जब आप एक के कारण एक स्टैक-ट्रेस देखते हैं, तो आप ConcurrentModificationException
तुरंत यह नहीं मान सकते कि इसका कारण असुरक्षित मल्टी-थ्रेडेड एक्सेस टू है Collection
। आपको यह निर्धारित करने के लिए स्टैक-ट्रेस की जांच करनी चाहिए कि किस वर्ग Collection
ने अपवाद को फेंक दिया ( कक्षा का एक तरीका प्रत्यक्ष या अप्रत्यक्ष रूप से इसे फेंक दिया जाएगा), और किस Collection
वस्तु के लिए। फिर आपको यह जांचना होगा कि उस वस्तु को कहां से संशोधित किया जा सकता है।
- सबसे आम कारण में
Collection
एक बढ़ाया for
लूप के भीतर संशोधन है Collection
। सिर्फ इसलिए कि आप Iterator
अपने स्रोत कोड में एक वस्तु नहीं देखते हैं इसका मतलब यह नहीं है कि वहाँ कोई नहीं Iterator
है! सौभाग्य से, दोषपूर्ण for
लूप के बयानों में से एक आमतौर पर स्टैक-ट्रेस में होगा, इसलिए त्रुटि को ट्रैक करना आमतौर पर आसान होता है।
- एक पेचीदा मामला तब होता है जब आपका कोड
Collection
ऑब्जेक्ट के संदर्भ में चारों ओर से गुजरता है । ध्यान दें कि संग्रह के अनम्य विचार (जैसे कि द्वारा निर्मित Collections.unmodifiableList()
) संशोधित संग्रह के संदर्भ को बनाए रखते हैं, इसलिए "अनमॉडिफ़ेबल" संग्रह पर पुनरावृत्ति अपवाद को फेंक सकती है (संशोधन कहीं और किया गया है)। आपके अन्य विचारCollection
, जैसे उप सूचियाँ , Map
प्रवेश सेट और Map
मुख्य सेट भी मूल (परिवर्तनीय) के संदर्भ को बनाए रखते हैं Collection
। यह थ्रेड-सेफ के लिए भी एक समस्या हो सकती है Collection
, जैसे CopyOnWriteList
; यह मत मानो कि थ्रेड-सुरक्षित (समवर्ती) संग्रह कभी अपवाद नहीं फेंक सकता है।
- कौन से ऑपरेशन संशोधित कर
Collection
सकते हैं कुछ मामलों में अप्रत्याशित हो सकता है। उदाहरण के लिए, LinkedHashMap.get()
इसके संग्रह को संशोधित करता है ।
- सबसे कठिन मामलों रहे हैं जब अपवाद है एक से अधिक थ्रेड द्वारा समवर्ती संशोधन के कारण।
समवर्ती संशोधन त्रुटियों को रोकने के लिए प्रोग्रामिंग
जब संभव हो, किसी Collection
ऑब्जेक्ट के सभी संदर्भों को सीमित करें , इसलिए समवर्ती संशोधनों को रोकना आसान है। Collection
एक private
ऑब्जेक्ट या एक स्थानीय चर बनाएं , और Collection
विधियों से या उसके पुनरावृत्तियों के संदर्भ न लौटें । फिर उन सभी स्थानों की जांच करना बहुत आसान है जहां Collection
संशोधित किया जा सकता है। यदि Collection
कई थ्रेड्स का उपयोग किया जाना है, तो यह सुनिश्चित करना व्यावहारिक है कि थ्रेड्स Collection
उपयुक्त सिंक्रोनाइजेशन और लॉकिंग के साथ ही एक्सेस करते हैं ।