首页 > 解决方案 > 不确定如何清除 concurrentModificationException

问题描述

试图理解为什么我不能创建一个新对象。我有一个缓慢出现的生成对象,一旦完成第 5 帧,它应该生成一个新对象并死亡。它抛出了一个 java.util.ConcurrentModificationException,我查了一下,但不明白。我想也许它调用了太多的鸡,所以我确实尝试创建一个函数来从不同的类调用它。当从另一个班级调用时,它会增加一行。它说的是字符串,但随后被挂在同一个异常上。

@Override
public void die() {
//this is set up to find the last animation frame
float x = location.getX();
float y = location.getY();
int orient = orientation;
    if(animSpawnRight.getIndex() == 4){
        //spawn chicken
        //then die
        handler.getWorld().getChickenSpawner().setHoleFalse(location);

        //executes to here and doesn't read string

        System.out.print("ARG CHICKENS not working!" + x + " , " + y + " , " + orientation);
        handler.getWorld().getEntityManager().addEntity(new Chicken(handler, x, y, orientation));
        super.setActive(false);
    }
}

错误日志将我带到我的实体管理器:

public void tick(){
    Iterator<Entity> it = entities.iterator();
    while(it.hasNext()){
        Entity e = it.next();
        e.tick();
        if(!e.isActive())
             //it.remove() below is the problem
            it.remove();
    }
    entities.sort(renderSorter);
}

目标:ChickenSpawner,它基本上是监视一个计时器,产生一个小鸡产卵对象。ChickenSpawning 对象播放一个简短的动画,然后调用新的鸡。( spawningChicken 和 Chicken 对象是分开的,因为这样更容易确保您不能提前射击。

(我什至尝试注释掉: super.setActive(false); 但这也不起作用)。是不是叫的鸡太多了?如果是这样,我如何让它只调用一个?我在多线程方面有点挣扎。

编辑 e.tick() 为实体管理器持有的所有“实体”调用类 tick。

而且我忘记了我出于某种原因将 die() 放在了 chickenSpawning 中——这可能是一种超级懒惰的方式来在完成它如何连接到所有东西之前查看 chickenspawning 动画。

@Override
public void tick() {
    animSpawnUp.tick();
    animSpawnDown.tick();
    animSpawnLeft.tick();
    animSpawnRight.tick(); 
    die();
}

那么它是同时删除和存在的吗?

标签: javaexception2d-gamesconcurrentmodificationspawning

解决方案


@Joni 的诊断是正确的。

我可以想到两种实用的方法来解决这个问题:

  1. 使用互斥锁来防止任何其他线程在tick()迭代实体列表时访问或更新它。(并对其进行排序!)请注意,当涉及多个线程时,CCME可能是您遇到更大问题的证据。如果您有多个线程在没有充分同步的情况下访问/更新共享数据结构,您可能会遇到阴险的“内存模型”错误。

  2. 使用 aCopyOnWriteList作为列表。它具有并发属性,可确保您不会遇到 CCME 或“内存模型”错误。

@Joni 提出的解决方案涉及 CCME,但不涉及潜在的“内存模型”错误。

最后,如果实时性能是一个问题,您可能不应该在每个“滴答”上对列表进行排序。事实上,使用 aConcurrentSkipListSet而不是列表可能会更好。(假设排序标准是不变的。)


推荐阅读