![](/img/trans.png)
[英]ConcurrentModificationException when iterate through List
[英]Receiving ConcurrentModificationException when attempting to iterate through HashMap
我正在處理我正在進行的項目的問題。 有一個運行程序的主循環,它每幀都調用update()
方法。
我有一個包含HashMap<ChunkPos, Chunk>
的World
的對象,其中ChunkPos
是一個數據結構,其xyz位置代表Chunk
在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();
}
}
}
但是,當我運行該程序時,我在此行收到一個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.