簡體   English   中英

嘗試迭代HashMap時接收ConcurrentModificationException

[英]Receiving ConcurrentModificationException when attempting to iterate through HashMap

我正在處理我正在進行的項目的問題。 有一個運行程序的主循環,它每幀都調用update()方法。

我有一個包含HashMap<ChunkPos, Chunk>World的對象,其中ChunkPos是一個數據結構,其xyz位置代表ChunkWorld的位置

我試圖在我的更新函數中遍歷我的世界中的所有塊,因為每個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();
        }
    }
}

但是,當我運行該程序時,我在此行收到一個ConcurrentModificationException

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

我已經嘗試了多種不同的迭代HashMap的方法,但每次我都會遇到同樣的錯誤。 我究竟做錯了什么?

如果它有幫助,這是完整的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)

只是想在這里做一個說明:我最終最終實現了一個WorldChangeScheduler,它可以安排在世界迭代並更新后對世界進行更改。 這使得它更加強大,並且具有額外的好處,我可以稍后返回並將這些WorldChanges轉換為其他人使用我的引擎可以掛鈎的事件。

這里ConcurrentModificationException意味着在迭代期間修改了映射而不使用迭代器。

obj.update(); 修改world.getChunkMap()映射,或者您有另一個線程,它在當前void update()方法的迭代過程中同時添加或刪除此相同映射的元素。
因為在顯示的代碼中沒有對地圖進行任何修改。

好吧,這段代碼造成了麻煩

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

使用迭代器並調用更新

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

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

HashMap不是線程安全的,因此在迭代時,當其他線程發生結構修改時,迭代器會快速失敗。

通過使用ConcurrentHashMap替換Map實現,您將防止此類問題,但鎖定將應用於更新操作,這將影響其性能。 如果期望可預測數量的線程同時更新此Map,則可以使用ConcurrentHashMap的concurrencyLevel參數配置並發級別思想。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM