为什么我要用迭代器获取java.util.ConcurrentModificationException?
我正在尝试编写一个游戏,所以每一帧我都调用doDraw()方法,其中我使用迭代器循环遍历所有游戏对象,并将它们全部打印在屏幕上:为什么我要用迭代器获取java.util.ConcurrentModificationException?,java,multithreading,concurrency,iterator,Java,Multithreading,Concurrency,Iterator,我正在尝试编写一个游戏,所以每一帧我都调用doDraw()方法,其中我使用迭代器循环遍历所有游戏对象,并将它们全部打印在屏幕上: Iterator<GameObject> itr = mObjList.iterator(); while (itr.hasNext()) { GameObject obj = itr.next(); // this line gives me the error ... // print objec
Iterator<GameObject> itr = mObjList.iterator();
while (itr.hasNext()) {
GameObject obj = itr.next(); // this line gives me the error
...
// print object
}
大多数情况下,它是有效的。但有时我会犯这样的错误:
java.util.ConcurrentModificationException
从带有“itr.next()”的行中。根据我在谷歌上搜索到的内容,我认为这是因为click()事件有时会在draw()完成绘制每个对象之前发生,因此它会在迭代器使用列表时更改列表。我想这是怎么回事
但我对线程没有经验。我怎么可能解决这个问题?也许我做错了,我应该使用完全不同的方法在屏幕上打印所有对象?解决方案是不要使用迭代器,或者在列表之间进行乒乓,这样您正在修改的列表就不是您正在迭代的对象。您也可以尝试使用同步,但这需要一些相当复杂的技能才能在不造成死锁的情况下做好工作。解决方案是不要使用迭代器,或者在列表之间进行乒乓,以便您正在修改的列表不是您正在迭代的列表。您也可以尝试使用同步,但这需要一些相当复杂的技能才能在不造成死锁的情况下做好。。。特别是因为它们似乎是随机发生的。使用迭代器遍历集合时,不能修改集合(除非使用迭代器的remove方法,但这是一个例外)。这样做会导致您看到的异常。。。但只是有时候。只有在遍历迭代器时正确调用mObjList.add时,才会发生此错误。nooo,同步错误非常严重。。。特别是因为它们似乎是随机发生的。使用迭代器遍历集合时,不能修改集合(除非使用迭代器的remove方法,但这是一个例外)。这样做会导致您看到的异常。。。但只是有时候。只有在遍历迭代器时正确调用mObjList.add时才会发生错误。如果预期的读取和遍历次数远远超过列表的更新次数,请使用 否则,在迭代和变异时,在列表(或专用互斥对象)上同步:
private List<GameObject> mObjList = /* whatever */;
private final Object mListMutex = new Object();
// snip...
synchronized (mListMutex) {
for (GameObject obj : mObjList) {
// do your thang
}
}
// snip...
public void click(int x, int y) {
GameObject obj = new GameObject(x, y);
synchronized (mListMutex) {
mObjList.add(obj);
}
}
private List mObjList=/*无论什么*/;
私有最终对象mListMutex=新对象();
//剪断。。。
已同步(mListMutex){
用于(游戏对象对象:mObjList){
//做你的工作
}
}
//剪断。。。
公共无效单击(整数x,整数y){
GameObject obj=新的GameObject(x,y);
已同步(mListMutex){
移动列表添加(obj);
}
}
如果预期的读取和遍历次数远远超过列表的更新次数,请使用
否则,在迭代和变异时,在列表(或专用互斥对象)上同步:
private List<GameObject> mObjList = /* whatever */;
private final Object mListMutex = new Object();
// snip...
synchronized (mListMutex) {
for (GameObject obj : mObjList) {
// do your thang
}
}
// snip...
public void click(int x, int y) {
GameObject obj = new GameObject(x, y);
synchronized (mListMutex) {
mObjList.add(obj);
}
}
private List mObjList=/*无论什么*/;
私有最终对象mListMutex=新对象();
//剪断。。。
已同步(mListMutex){
用于(游戏对象对象:mObjList){
//做你的工作
}
}
//剪断。。。
公共无效单击(整数x,整数y){
GameObject obj=新的GameObject(x,y);
已同步(mListMutex){
移动列表添加(obj);
}
}
我想在@aleph\u null的答案中添加内容@aleph_null是正确的,当您尝试在集合上进行迭代时修改集合时会发生此异常——只允许迭代器上的remove()
方法。迭代器试图保护自己不受其下集合发生的更改的影响
但是,我不建议将同步作为正确的解决方案。如果您需要在处理列表时将内容添加到列表中,那么我建议您添加到另一个列表中,然后在停止迭代后调用addAll()
。当然,GC更密集,但更清洁
编辑:
抱歉,我忽略了一个事实,
click()
是另一个线程传递的异步事件。我假设click()
是在循环内部调用的。当您在click()
中添加时,必须围绕列表进行同步,并围绕addAll()
进行同步。您可以使用AtomicReference
记录单击,然后在迭代器完成后对其进行操作,但前提是您保证一次只单击一个项目。我想添加@aleph\u null的答案@aleph_null是正确的,当您尝试在集合上进行迭代时修改集合时会发生此异常——只允许迭代器上的remove()
方法。迭代器试图保护自己不受其下集合发生的更改的影响
但是,我不建议将同步作为正确的解决方案。如果您需要在处理列表时将内容添加到列表中,那么我建议您添加到另一个列表中,然后在停止迭代后调用addAll()
。当然,GC更密集,但更清洁
编辑:
抱歉,我忽略了一个事实,
click()
是另一个线程传递的异步事件。我假设click()
是在循环内部调用的。当您在click()
中添加时,必须围绕列表进行同步,并围绕addAll()
进行同步。您可以使用AtomicReference
记录单击,然后在迭代器完成后对其进行操作,但前提是您保证一次只单击一个项目。您对为什么会得到ConcurrentModificationException
的猜测是正确的
要解决此问题,您可以在列表本身上进行同步:
synchronized(mObjList) {
Iterator itr = mObjList.iterator();
while (itr.hasNext()) {
// ...
}
}
这将允许线程获得列表本身的锁。如果从o包装对列表的访问