Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么我要用迭代器获取java.util.ConcurrentModificationException?_Java_Multithreading_Concurrency_Iterator - Fatal编程技术网

为什么我要用迭代器获取java.util.ConcurrentModificationException?

为什么我要用迭代器获取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

我正在尝试编写一个游戏,所以每一帧我都调用doDraw()方法,其中我使用迭代器循环遍历所有游戏对象,并将它们全部打印在屏幕上:

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包装对列表的访问