简体   繁体   English

尝试迭代HashMap时接收ConcurrentModificationException

[英]Receiving ConcurrentModificationException when attempting to iterate through HashMap

I am having issues with a project I am working on. 我正在处理我正在进行的项目的问题。 There is a main loop that runs the program which calls the update() method every frame. 有一个运行程序的主循环,它每帧都调用update()方法。

I have an object that is a World which contains a HashMap<ChunkPos, Chunk> where a ChunkPos is a data structure that has an xyz position which represents a Chunk 's position in the World 我有一个包含HashMap<ChunkPos, Chunk>World的对象,其中ChunkPos是一个数据结构,其xyz位置代表ChunkWorld的位置

I am attempting to iterate through all the Chunks in my the world in my update function, as each Chunk has it's own ArrayList of GameObject that has all of the objects inside this chunk of the world. 我试图在我的更新函数中遍历我的世界中的所有块,因为每个Chunk都有自己的GameObject ArrayList,其中包含了这个世界中的所有对象。

public void update() {
    HashMap<ChunkPos, Chunk> chunkMap = world.getChunkMap();
    Iterator<Map.Entry<ChunkPos, Chunk>> it = chunkMap.entrySet().iterator();
    while(it.hasNext()) {
        Map.Entry<ChunkPos, Chunk> item = it.next();
        ArrayList<GameObject> chunkObjects = item.getValue().getObjects();
        for(GameObject obj : chunkObjects) {
            obj.update();
        }
    }
}

However, when I run the program, I am receiving a ConcurrentModificationException at this line: 但是,当我运行该程序时,我在此行收到一个ConcurrentModificationException

Map.Entry<ChunkPos, Chunk> item = it.next();

I've tried multiple different ways of iterating through the HashMap, but each time I end up with this same error. 我已经尝试了多种不同的迭代HashMap的方法,但每次我都会遇到同样的错误。 What am I doing wrong? 我究竟做错了什么?

Here is the full StackTrace if it helps: 如果它有帮助,这是完整的StackTrace:

Exception in thread "main" java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextNode(HashMap.java:1429)
at java.util.HashMap$EntryIterator.next(HashMap.java:1463)
at java.util.HashMap$EntryIterator.next(HashMap.java:1461)
at com.anzanama.lwjgl3d.Game.Game.update(Game.java:40)
at com.anzanama.lwjgl3d.Game.Game.loop(Game.java:31)
at com.anzanama.lwjgl3d.Main.main(Main.java:15)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)

Just wanted to make a note here: I eventually ended up implementing a WorldChangeScheduler that would schedule changes to be made to the world once it has iterated through the whole world and updated it. 只是想在这里做一个说明:我最终最终实现了一个WorldChangeScheduler,它可以安排在世界迭代并更新后对世界进行更改。 This makes it more robust and has the added benefit that I can later go back and turn these WorldChanges into events that other people using my engine can hook into. 这使得它更加强大,并且具有额外的好处,我可以稍后返回并将这些WorldChanges转换为其他人使用我的引擎可以挂钩的事件。

Here ConcurrentModificationException means that the map was modified during iteration without using the iterator. 这里ConcurrentModificationException意味着在迭代期间修改了映射而不使用迭代器。

Either obj.update(); obj.update(); modifies the world.getChunkMap() map or you have another thread that concurrently adds or removes an element of this same map during the iteration of the current void update() method. 修改world.getChunkMap()映射,或者您有另一个线程,它在当前void update()方法的迭代过程中同时添加或删除此相同映射的元素。
Because in the shown code there is not any modification of the map. 因为在显示的代码中没有对地图进行任何修改。

Well, this code is causing the trouble 好吧,这段代码造成了麻烦

ArrayList<GameObject> chunkObjects = item.getValue().getObjects();
for(GameObject obj : chunkObjects) {
    obj.update();
}

Use an Iterator and call update 使用迭代器并调用更新

Iterator<GameObject> iter = item.getValue().getObjects().iterator();

while (iter.hasNext()) {
    GameObject obj = iter.next();
    obj.update();
}

HashMap is not thread-safe, so iterators fail fast when structural modifications happen by other threads, while iterating. HashMap不是线程安全的,因此在迭代时,当其他线程发生结构修改时,迭代器会快速失败。

By replacing your Map implementation with ConcurrentHashMap , you will prevent such issues, but locking will apply on the update operations, which will affect their performance. 通过使用ConcurrentHashMap替换Map实现,您将防止此类问题,但锁定将应用于更新操作,这将影响其性能。 You can configure concurrency level, thought, using the concurrencyLevel parameter of the ConcurrentHashMap, if a predictable number of threads is expected to update this Map concurrently. 如果期望可预测数量的线程同时更新此Map,则可以使用ConcurrentHashMap的concurrencyLevel参数配置并发级别思想。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM