本文介绍了ConcurrentModificationException甚至在LinkedHashMap上使用Collections.sychronizedMap的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在我的类中使用了一个Map对象,我已经与LinkedHashMap的Collections.synchronizedMap()同步,如下所示:

I'm using a Map object in my class that I've synchronized with Collections.synchronizedMap() for a LinkedHashMap like so:

private GameObjectManager(){
        gameObjects = Collections.synchronizedMap(new LinkedHashMap<String, GameObject>());
}

我在这个函数的第三行得到一个并发修改异常:

I'm getting a concurrent modification exception on the third line of this function:

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

我在迭代地图的所有其他位置,我按照文档同步地图。

All other locations where I am iterating through the Map, I am synchronizing on the map per the docs.

我的类中还有其他函数使用这个Map(同步的!),并且它们放置()和remove()对象,但这应该无关紧要。我究竟做错了什么?请询问更多代码,不确定还要放什么。

There are other functions in my class that use this Map (the synchronized one!) and they put() and remove() objects, but this shouldn't matter though. What am I doing wrong? Please ask for more code, not sure what else to put.

哦,还有日志信息:

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)


推荐答案

尽管有这个名字,但这与多线程意义上的并发性无关。除非在迭代器上调用 remove(),否则在迭代时不能修改此映射。也就是说,你有... ...

Despite the name, this has nothing to do with concurrency in the multithreading sense. You can't modify this map while iterating on it, except by invoking remove() on the iterator. That is, where you have...

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

如果 ... 修改 INSTANCE.gameObjects.values()(例如,删除或添加元素),下次调用 next()迭代器(隐含在 for 循环)将抛出该异常。

if the ... modifies INSTANCE.gameObjects.values() (for instance, removing or adding an element), the next invocation to next() on the iterator (which is implicit to the for loop) will throw that exception.

大多数情况都是如此集合和地图实现。 javadoc通常指定该行为,但并不总是显而易见。

This is true of most collections and Map implementations. The javadocs usually specify that behavior, though not always obviously.

修正:


  • 如果您要执行的操作是删除元素,则需要显式获取 Iterator< GameObject> 并调用 remove( )就可以了。

for (Iterator<GameObject> iter = INSTANCE.getObjects().values(); iter.hasNext(); ;) {
     GameObject object = iter.next();
     if (someCondition(object)) {
         iter.remove();
     }
 }


  • 如果您正在尝试添加元素,需要创建一个临时集合来保存要添加的元素,然后迭代器完成后, putAll(temporaryMapForAdding)

  • If you're trying to add an element, you need to create a temporary collection to hold the elements you want to add, and then after the iterator is finished, putAll(temporaryMapForAdding).
  • 这篇关于ConcurrentModificationException甚至在LinkedHashMap上使用Collections.sychronizedMap的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

    07-05 10:49