Java-并发修改异常
我收到以下代码的并发修改异常:Java-并发修改异常,java,multithreading,exception,concurrency,Java,Multithreading,Exception,Concurrency,我收到以下代码的并发修改异常: for(Iterator<Tile> iter = spawner.activeTiles.iterator(); iter.hasNext();) { Tile tile = iter.next(); canvas.drawRect(tile, tile.getColor()); } for(Iterator iter=spawner.activeTiles.Itera
for(Iterator<Tile> iter = spawner.activeTiles.iterator(); iter.hasNext();) {
Tile tile = iter.next();
canvas.drawRect(tile, tile.getColor());
}
for(Iterator iter=spawner.activeTiles.Iterator();iter.hasNext();){
Tile-Tile=iter.next();
drawRect(tile,tile.getColor());
}
我知道在迭代过程中(在迭代过程中添加/删除)更改时,会发生并发修改。我也明白,在多线程处理时可能会发生这种情况,我认为这就是我的问题所在
在我的游戏中,我有一些运行在线程上的计时器。我有一个生成程序,它在每个刻度上为activeTiles添加值。然后我有两个计时器,一个用于淡入,一个用于淡出。在不放弃我的游戏的情况下,当淡出结束时,或者当玩家轻触互动程序时,互动程序基本上从列表中删除。因此,有一些情况下会从磁贴列表中删除磁贴:
for(Iterator<Tile> iter = spawner.activeTiles.iterator(); iter.hasNext();) {
Tile tile = iter.next();
if(tile.contains(x, y) && tile.equals(spawner.activeTiles.get(0))) {
vibrator.vibrate(50);
tile.setBroken(true);
score ++;
spawner.setTileDelayInfo();
iter.remove();
for(Iterator iter=spawner.activeTiles.Iterator();iter.hasNext();){
Tile-Tile=iter.next();
if(tile.contains(x,y)&&tile.equals(spawner.activeTiles.get(0))){
振动器。振动(50);
tile.setBroken(真);
分数++;
spawner.setTileDelayInfo();
iter.remove();
在每次新生成之前,它会删除所有失败的分幅:
private void removeFailedTiles() {
for(Iterator<Tile> iter = activeTiles.iterator(); iter.hasNext();) {
Tile tile = iter.next();
if(tile.isFailed()) {
iter.remove();
}
}
}
private void removedfailedtiles(){
for(迭代器iter=activeTiles.Iterator();iter.hasNext();){
Tile-Tile=iter.next();
if(tile.isFailed()){
iter.remove();
}
}
}
它几乎是随机发生的。所以我认为它与时间有关,但我对这种异常不熟悉,不知道该查找什么,也不知道为什么会发生这种情况。多线程可能是
ConcurrentModificationException
的一个来源。当一个线程修改collect的结构时,可能会发生这种情况当另一个线程有一个迭代器对其进行迭代时,这可能会导致应用程序出现意外状态,因为当一段代码需要一致的数据视图时,集合的状态会发生变化。这是在迭代平铺
的集合时需要的
您需要同步对activeTiles
集合的访问。任何在结构上修改此集合(添加或删除)或对其进行迭代的操作都必须在此集合上同步
在迭代或在结构上修改activeTiles
的所有代码周围添加一个synchronized(activeTiles)
块。这包括您在此处提供的所有3个代码片段
或者,您可以使与您的代码段相对应的3个方法同步
无论哪种方式,在另一个线程完成其syncrhonized
部分之前,没有任何其他线程可以执行任何synchronized
块,从而防止ConcurrentModificationException
使用支持元素删除的迭代器删除元素是不安全的,当您在另一个线程中迭代集合时
在迭代之前,请在activeTiles上的所有线程中获取一个。您可能希望使列表线程安全。请使用
请注意,在对该列表进行迭代时,必须对其进行同步:
synchronized (threadSafeActiveTiles) {
for (Iterator<Tile> it = threadSafeActiveTiles.iterator(); it.hasNext();) {
Tile tile = it.next();
// ...
}
}
synchronized(threadSafeActiveTiles){
for(Iterator it=threadSafeActiveTiles.Iterator();it.hasNext();){
Tile Tile=it.next();
// ...
}
}
然后,您可以安全地让多个线程修改列表,这似乎就是您的情况
Collections.synchronizedList()
返回的列表使您无需在该列表上的单个操作中使用同步块(如上),如add(e)
,size()
,get(i)
等等…好消息是:您在问题中找到了问题的根本原因-您不能让多个线程同时访问列表,除非它们都只是在阅读
您可以通过两种方式之一来解决这个问题,具体取决于代码的其余部分是如何操作的。最“正确”的方式是steffen的回答:任何列表访问都应该使用synchronized
块进行保护,这包括在任何列表迭代的整个过程中保持锁定。请注意,如果这样做,您只需要做很少的工作在保持锁的同时尽可能多地调用侦听器—特别是,在保持锁的同时执行任何类型的侦听器回调都不是一个好主意
第二种选择是使用线程安全的,不需要任何外部同步,但是对列表的任何修改(添加/删除/替换调用)都会变得非常昂贵。如果它“似乎是随机发生的”这可能是多线程问题。@Ata,他使用的是迭代器,不是同一个问题。事实上,使用迭代器是这个问题的答案,所以他这样做是正确的!添加synchronized on函数将同步对函数的访问,而不是对函数中使用的数据结构的访问。两个不同的rent函数正在访问相同的列表。@Ata在这些方法上添加synchronized
将锁定对象实例,该对象实例在每个线程中都是相同的对象实例。效果与synchronized(activeTiles)中的效果相同
;迭代或修改activeTiles
的代码一次只能由一个线程执行。是的,所有迭代activeTiles
或在结构上修改它的代码都必须是同步的。语法是什么?我从未使用过同步的before@KyleJensen有和。synchr如果在列表上迭代,onizedList是不够的,因为在整个迭代过程中没有锁,所以仍然可以获得Concurren
synchronized (threadSafeActiveTiles) {
for (Iterator<Tile> it = threadSafeActiveTiles.iterator(); it.hasNext();) {
Tile tile = it.next();
// ...
}
}