5

मैं मेरी कक्षा में एक मानचित्र उद्देश्य यह है कि मैं बहुत की तरह एक LinkedHashMap के लिए Collections.synchronizedMap() के साथ समन्वयित किया है उपयोग कर रहा हूँ इस समारोह की तीसरी लाइन पर एक समवर्ती संशोधन अपवाद हो रही:ConcurrentModificationException भी एक LinkedHashMap पर Collections.sychronizedMap उपयोग करने के साथ

public static void frameElapsed(float msElapsed){ 
    if(!INSTANCE.gameObjects.isEmpty()){ 
     synchronized(INSTANCE.gameObjects){ 
      for(GameObject object : INSTANCE.gameObjects.values()){...} 
     } 
    } 
} 

अन्य सभी स्थान जहाँ मैं मानचित्र के माध्यम से पुनरावृत्ति हूँ, मैं डॉक्स प्रति नक्शे पर सिंक्रनाइज़ कर रहा हूँ।

मेरी कक्षा में अन्य फ़ंक्शन हैं जो इस मानचित्र (सिंक्रनाइज़ किए गए एक!) का उपयोग करते हैं और वे ऑब्जेक्ट डालते हैं() और हटाते हैं() ऑब्जेक्ट्स, लेकिन इससे कोई फर्क नहीं पड़ता। मैं क्या गलत कर रहा हूं? कृपया अधिक कोड मांगें, सुनिश्चित न करें कि और क्या रखा जाए।

ओह, और लॉग संदेश:

08-20 15:55:30.109: E/AndroidRuntime(14482): FATAL EXCEPTION: GLThread 1748 
08-20 15:55:30.109: E/AndroidRuntime(14482): java.util.ConcurrentModificationException 
08-20 15:55:30.109: E/AndroidRuntime(14482): at  java.util.LinkedHashMap$LinkedHashIterator.nextEntry(LinkedHashMap.java:350) 
08-20 15:55:30.109: E/AndroidRuntime(14482): at  java.util.LinkedHashMap$ValueIterator.next(LinkedHashMap.java:374) 
08-20 15:55:30.109: E/AndroidRuntime(14482): at  package.GameObjectManager.frameElapsed(GameObjectManager.java:247) 
08-20 15:55:30.109: E/AndroidRuntime(14482): at  package.GamekitInterface.render(Native Method) 
08-20 15:55:30.109: E/AndroidRuntime(14482): at  package.GamekitInterface.renderFrame(GamekitInterface.java:332) 
08-20 15:55:30.109: E/AndroidRuntime(14482): at  com.qualcomm.QCARSamples.ImageTargets.GameEngineInterface.onDrawFrame(GameEngineInterface.java:107) 
08-20 15:55:30.109: E/AndroidRuntime(14482): at  android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1516) 
08-20 15:55:30.109: E/AndroidRuntime(14482): at  android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1240) 
+0

आप ** gameObjects ** जो कुछ कार्यों का उपयोग का उपयोग करना चाहिए अगर आप दो बार GameObjectManager() कहते हैं; पहले gameObjects और दूसरा gameObjects एक ही वस्तु नहीं हैं, इसलिए ConcurrentModificationException –

+0

कारण मुझे समझ नहीं आता कि तुम क्या कहा सकता है। लेकिन मैंने नोटिस किया कि मुझे सिंक्रनाइज़ करने के बाद ऐसा करना चाहिए। क्या तुमने यही कहा? – mpellegr

उत्तर

12

नाम के बावजूद, इसका बहुसंख्यक अर्थ में सहमति के साथ कुछ लेना देना नहीं है। इटरेटर पर remove() को आमंत्रित करने के अलावा, आप इसे चालू करते समय इस मानचित्र को संशोधित नहीं कर सकते हैं। यही कारण है, जहां है ...

for(GameObject object : INSTANCE.gameObjects.values()){...} 

अगर ... को संशोधित करता INSTANCE.gameObjects.values() (उदाहरण के लिए निकाल देते हैं या कोई तत्व जोड़), पुनरावर्तक पर next() के बगल में मंगलाचरण (जो for पाश करने के लिए निहित है) होगा उस अपवाद को फेंक दो।

यह अधिकांश संग्रह और मानचित्र कार्यान्वयन के बारे में सच है। Javadocs आमतौर पर उस व्यवहार को निर्दिष्ट करते हैं, हालांकि हमेशा स्पष्ट रूप से नहीं।

सुधार:

  • है कि आप क्या करने की कोशिश कर रहे हैं तत्व निकाल है, तो आप स्पष्ट रूप से Iterator<GameObject> हो और उस पर remove() कॉल करने के लिए की जरूरत है।

    for (Iterator<GameObject> iter = INSTANCE.getObjects().values(); iter.hasNext(); ;) { 
        GameObject object = iter.next(); 
        if (someCondition(object)) { 
         iter.remove(); 
        } 
    } 
    
  • आप एक तत्व जोड़ने के लिए कोशिश कर रहे हैं, तो आप तत्वों आप जोड़ना चाहते हैं पकड़ करने के लिए एक अस्थायी संग्रह बनाने की जरूरत है, और फिर के बाद इटरेटर, putAll(temporaryMapForAdding) समाप्त हो गया है।
+0

मैं अपने द्वारा किए गए किसी भी पुनरावृत्ति में कुछ भी जोड़ या हटा नहीं रहा हूं। मैं अन्य कार्यों में जोड़ रहा हूं और हटा रहा हूं जिन्हें किसी अन्य धागे से बुलाया जाता है। क्या इसकी अनुमति नहीं है? – mpellegr

+1

वैसे हाँ, यह 'सिंक्रनाइज़' ब्लॉक का पूरा बिंदु है। अन्य थ्रेड मानचित्र पर किसी भी तरीके से 'सिंक्रनाइज़ किए गए' ब्लॉक समाप्त होने तक नहीं आ पाएगा। लेकिन यह इस समस्या का कारण नहीं है; यह समस्या केवल एक धागे के साथ मौजूद होगी। – yshavit

+0

आह, मैं देख रहा हूं कि क्या हो रहा है! फ़ंक्शन कॉल के लंबे निशान के माध्यम से, पुनरावृत्ति के दौरान मानचित्र में ऑब्जेक्ट जोड़े जा रहे हैं। मैं इसे उत्तर के रूप में चिह्नित करूंगा, लेकिन क्या आपको पता है कि मैं पहले से तर्क का उपयोग कर सकता हूं जो मानचित्र से ऑब्जेक्ट्स को जोड़/हटा रहा है, अगर मैं चिंतित हूं या नहीं? – mpellegr

2

Collections.synchronizedMap() आप जब बार-बार दोहराना मदद नहीं करता है। यह सिर्फ आपके मानचित्र को परमाणु रूप से रखे/निकालने/निकालने का कार्य करेगा (इसका मतलब है कि आपके पास दो ऐसे ऑपरेशन एक साथ चलने वाले नहीं होंगे)।

पुनरावृत्त करते समय, आप प्रत्येक तत्व को लाते हैं और इसके साथ कुछ करते हैं। लेकिन क्या होगा यदि आप अपने पुनरावृत्ति के भीतर बहुत ही तत्व पर काम कर रहे हैं क्योंकि आपके वर्तमान तत्व को किसी अन्य धागे से हटा दिया जाता है? आप अपने Integer मानों का योग कंप्यूटिंग कर रहे हैं, उदाहरण के लिए, तत्व:

यह वही अपवाद को रोकने के लिए, जैसा कि आप एक परिणाम है कि अपने नक्शे के किसी भी वास्तविक स्नैपशॉट के अनुरूप नहीं है मिल सकता है कोशिश कर रही है आप पहले ही जोड़े गए हैं और हटाए जाने पर दूसरों को जोड़ा जा सकता है, इसलिए आप एक योग के साथ समाप्त हो जाएंगे जो आपके मानचित्र के किसी भी "स्नैपशॉट" से मेल नहीं खाता है।

के लिए आप कार्य करना चाहते हैं क्या, एकमात्र समाधान कुछ सिंक्रनाइज़ ब्लॉक के भीतर पूरी यात्रा प्रदर्शन करने के लिए किया जाएगा, लेकिन यह अनिवार्य है कि आप एक ही अपने नक्शे के संचालन के द्वारा प्रयोग किया मॉनीटर पर सिंक्रनाइज़ करें। और Collections.syncrhonizedMap() एक रैपर प्रदान करता है जो कुछ आंतरिक mutex, पर this संदर्भ पर सिंक्रनाइज़ नहीं करता है। इसलिए, पुनरावृत्ति के दौरान आपके मानचित्र में किसी भी संशोधन को रोकने का आपका प्रयास विफल हो जाएगा।

+0

मैं सिंक्रनाइज़ेशन ब्लॉक में मानचित्र पर पुनरावृत्त करने के सभी उदाहरण रखता हूं। – mpellegr

+0

मैं देखता हूं ... मैं पूरी तरह से चूक गया; माफ़ कीजिये ! मैं आपको एक संकेत देने के लिए अपना जवाब संपादित करूंगा। –

+0

था आंतरिक आंतरिक म्यूटेक्स वास्तव में कन्स्ट्रक्टर में प्रदान किए गए डिफ़ॉल्ट मामलों पर 'यह' है। –

2

आप for-eachfor लूप के समान संस्करण का उपयोग कर रहे हैं। जावा में इस तरह के लूप में पुनरावृत्त संग्रह से तत्व जोड़ने या निकालने के लिए मना किया गया है। इस स्थिति से बचने के लिए, संग्रह इटरेटर का उपयोग करें। इटरेटर से, आप तत्वों को हटा सकते हैं।

संबंधित मुद्दे