java - ConcurrentModificationException 即使在 LinkedHashMap 上使用 Collections.sychronizedMap

标签 java multithreading synchronized linkedhashmap concurrentmodification

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

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

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

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

我遍历 map 的所有其他位置,我根据文档在 map 上同步。

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

哦,还有日志消息:

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)

最佳答案

尽管名称如此,但这与多线程意义上的并发无关。您不能在迭代时修改此 map ,除非调用 remove()在迭代器上。也就是说,你有...

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

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

大多数集合和 Map 实现都是如此。 javadocs 通常指定该行为,尽管并不总是很明显。

修复:

  • 如果您要尝试删除元素,则需要显式获取 Iterator<GameObject>并调用remove()在上面。

    for (Iterator<GameObject> iter = INSTANCE.getObjects().values(); iter.hasNext(); ;) {
         GameObject object = iter.next();
         if (someCondition(object)) {
             iter.remove();
         }
     }
    
  • 如果您尝试添加一个元素,您需要创建一个临时集合来保存您要添加的元素,然后迭代器完成后,putAll(temporaryMapForAdding) .

关于java - ConcurrentModificationException 即使在 LinkedHashMap 上使用 Collections.sychronizedMap,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18343989/

相关文章:

java - Android Studio EditText 字段给出 null 或 0

java - 为什么在大约 10 个内核后添加内核会使我的 Java 程序变慢?

java - glfwGetVideoMode(glfwGetPrimaryMonitor()) 不起作用

C++11 - 可以等待几个不同事件的线程?

java - 线程如何能够访问应该是 block 的同步块(synchronized block)?

java - 登录时 NTLM Spring 安全异常

python - 如何使用 'with' 语句对 Python 锁进行单元测试?

java - 不可变对象(immutable对象)如何帮助减少垃圾收集带来的开销?

java - 同步(对象) { } 问题

java - HashMap同步