एक का संशोधन Collectionकरते हुए बार-बार दोहराना के माध्यम से उस Collectionका उपयोग कर एक Iteratorहै की अनुमति नहीं के सबसे द्वारा Collectionकक्षाएं। जावा लाइब्रेरी Collectionइसे "समवर्ती संशोधन" के माध्यम से थोड़ी देर में संशोधित करने का प्रयास कहता है । यह दुर्भाग्य से एकमात्र संभव कारण बताता है कि एक साथ कई थ्रेड्स द्वारा संशोधन है, लेकिन ऐसा नहीं है। केवल एक धागे Collectionका उपयोग करके (उपयोग Collection.iterator()या बढ़ाया forलूप ) के लिए एक पुनरावृत्ति बनाना संभव है , पुनरावृत्ति शुरू करें (उपयोग Iterator.next(), या समकक्ष रूप से बढ़ाया forलूप के शरीर में प्रवेश ), संशोधित करेंCollection , फिर पुनरावृत्ति जारी रखें।
प्रोग्रामर की मदद करने के लिए, उन वर्गों के कुछ कार्यान्वयन गलत समवर्ती संशोधन का पता लगाने का प्रयास करते हैं, और यदि वे इसका पता लगाते हैं तो उन्हें फेंक देते हैं । हालांकि, सभी समवर्ती संशोधनों का पता लगाने की गारंटी देना सामान्य और संभव नहीं है। इसलिए गलत का गलत इस्तेमाल हमेशा फेक नहीं होता ।CollectionConcurrentModificationExceptionCollectionConcurrentModificationException
का प्रलेखन 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उपयुक्त सिंक्रोनाइजेशन और लॉकिंग के साथ ही एक्सेस करते हैं ।