无法从其他类添加到对象ArrayList

时间:2018-12-31 03:09:06

标签: java

通过将元素添加到位于另一个类的ArrayList中,我得到了一个并发修改异常。 (GUI程序)

Exception in thread "Thread-0" java.util.ConcurrentModificationException
at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:937)
at java.base/java.util.ArrayList$Itr.next(ArrayList.java:891)
at sentinel/entity.EntityManager.tick(EntityManager.java:35)
at sentinel/worlds.World.tick(World.java:80)
at sentinel/state.GameState.tick(GameState.java:25)
at sentinel/game.Game.tick(Game.java:72)
at sentinel/game.Game.run(Game.java:115)
at java.base/java.lang.Thread.run(Thread.java:844)

我尝试包含一个迭代器,因为我在Google上搜索了如何解决ConcurrentModificationException。但是,它没有帮助,或者我使用的是错误的。

这是我正在将元素添加到ArrayList的类。

public class SentryHive extends StaticEntity{

private long lastSpawnTimer, spawnCooldown = 1000, spawnTimer = spawnCooldown;
private Random r = new Random();

public SentryHive(Handler handler, double x, double y) {
    super(handler, x, y, tiles.Tiles.TILEWIDTH*3, tiles.Tiles.TILEHEIGHT*3);
    bounds.x = 32*3;
    bounds.y = 64*4 - 80;
    bounds.width = 50;
    bounds.height = 32;

}

@Override
public void tick() {
    SpawnSentry();
}

public void SpawnSentry() {

    spawnCooldown = r.nextInt(100) * 1000;
    spawnTimer += System.currentTimeMillis() - lastSpawnTimer;
    lastSpawnTimer = System.currentTimeMillis();

    //Iterator<Entity> it = handler.getWorld().getEntityManager().getEntities().iterator();
    //while (it.hasNext()) {
        if(spawnTimer >= spawnCooldown) {  
            handler.getWorld().getEntityManager().addEntity(new Sentry(handler, 1080, 910, 10, 10));
        }
   // }

    spawnTimer = 0;

}

这是我程序的一部分,其中添加了其他实体(如果需要):

public class World {

private int width, height;
private int[][] tiles;
private int[][] entities;
private int spawnx, spawny;
private Handler handler;
private EntityManager entityManager;
private State state;
private ItemManager itemManager;

public int requiredSentry = 0;

private Random r = new Random();
//fun: ALT command R to change all of the same word in a file

public World(Handler handler, String path, String topper) {
    this.handler = handler;

    entityManager = new EntityManager(handler, new Player(handler, 600, 600));
    itemManager = new ItemManager(handler);

    entityManager.addEntity(new SentryHive(handler, 980, 810));

    loadWorld(path);

    for(int i = 0; i < width; i++) {
        for(int j = 0; j < height; j++) {
            int temp = r.nextInt(1000);

            if(temp >=1 && temp <= 10) {
                entityManager.addEntity(new DyingTree(handler, i*64, j*64));
            } else if(temp >= 11 && temp <= 15) {
                entityManager.addEntity(new Sentry(handler, i*64, j*64, 10, 10));
            } else if(temp >= 21 && temp <= 25) {
                entityManager.addEntity(new Beetle(handler, i*64, j*64, 40, 40));
            } else if(temp == 30) {
                entityManager.addEntity(new BeetleRed(handler, i*64, j*64, 40, 40));
            }
        }
    }

    entityManager.getPlayer().setX(spawnx * Tiles.TILEWIDTH);
    entityManager.getPlayer().setY(spawny * Tiles.TILEHEIGHT);
}

下面是我的实体管理器类(如果需要):

public class EntityManager {

private Handler handler;
private Player player;
private ArrayList<Entity> entities;
private Comparator<Entity> renderSorter = new Comparator<Entity>() {
    @Override
    public int compare(Entity a, Entity b) {
        if(a.getY() + a.getHeight() < b.getY() + b.getHeight()) 
            return -1;
        return 1;
    }
};

public EntityManager(Handler handler, Player player) {
    this.handler = handler;
    this.player = player;
    entities = new ArrayList<Entity>();
    addEntity(player);
}

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

public void addEntity(Entity e) {
    entities.add(e);
}

我认为某个地方可能存在初始化或声明错误,我只希望列表添加实体并解决该错误,因为我的render方法可以将ArrayList中的所有内容绘制到屏幕上。

1 个答案:

答案 0 :(得分:2)

您的列表由多个线程使用,并且同时,如果一个线程尝试读取而另一个线程尝试写入,则将发生此异常,为避免这种情况,您可以使用CopyOnWriteArrayList list。 例: CopyOnWriteArrayList list = new CopyOnWriteArrayList <>();

使用此方法写入数据的成本更高,因此请阅读此api的所有优缺点。