我目前正在为学校开展一个小型项目,这是一场TowerDefense游戏。
初始化游戏时,会启动计算所有内容的线程。启动该线程后,我的代码跳转到循环,循环我的图形代码。我认为它正在使用2个线程。一个线程用于计算,另一个线程是“标准”线程,用于打开程序本身。
现在我想将Projectiles添加到我的塔楼。为此,我需要向我的Entity ArrayList添加一个新的Projectile对象。每当我尝试这样做时,它说
线程“main”中的异常java.util.ConcurrentModificationException
并指向我的图形循环所在的行,它试图循环我的实体数组。这是有道理的,因为当我的Projectiles被添加到这个数组时,我的图形循环尝试读取。我尝试使用“synchronized”,我想我知道如何使用它以及它的用途,但我不确定在我的代码中将它用于何处。我从昨天开始尝试解决这个问题,并且无法在互联网上找到任何解决方法。另外我不确定哪部分代码可以帮助你,如果你不明白我的程序是如何工作的,问题是什么,如果你需要什么,请随时问。
如果有人可以帮我解决这个问题会很棒,如果你还在读书,我已经要感谢你了
编辑:我认为这些是重要的代码:
世界更新方法:
private void updateRunning() {
waveTimer();
for (Entity e : entities) {
if (e.isMonster() && !block) {
e.toMonster().move();
if (e.toMonster().getHealth() <= 0)
entities.remove(e);
} else if (e.isTower()) {
e.toTower().setTarget(e.toTower().findTarget());
e.toTower().shoot();
} else if (e.isProjectile()) {
e.toProjectile().update();
}
}
}
渲染器循环方法:
private void updateRunning() {
cam.update();
for (Entity ent : world.getEntities()) {
ent.draw();
}
cursor.update();
cursor.draw(); // Must always be on bottom draw-methods, to be drawed
// on top of
// everything else
cam.refresh();
}
EDIT2
private void addWave() {
if (wave % 3 == 1) {
for (int i = 0; i < 6; i++) {
entities.add(new Monster(this, i + 1, path.getCoord(0).x,
path.getCoord(0).y - i * 57, 0.35f, Assetloader.monster01));
}
} else if (wave % 3 == 2) {
} else {
}
}
private void attack(Monster target, float damage) {
world.addEntity(new Projectile(world, vec.x, vec.y, 20, 20, target,
this, Assetloader.cursor01));
ready = false;
lastShot = System.currentTimeMillis();
}
public void addEntity(Entity e) {
this.entities.add(e);
}
答案 0 :(得分:2)
当您需要在多个线程中收集数据时,您应该使用支持并发的结构。在Java中,可以在java.util.concurrent
包中找到这样的类。对于您的情况,您应该使用CopyOnWriteArrayList
类而不是ArrayList
。
根据我的经验,使用ArrayList
或ArrayList
的并发支持变体不是这些情况的最佳选择。使用像ConcurrentLinkedQueue
这样的并发队列会更好。
答案 1 :(得分:0)
根据您的问题看起来,您似乎在多个线程之间共享数据结构。适当的类是java.util.Vector
,因为它(或多或少)是ArrayList
的同步版本
答案 2 :(得分:0)
您可以使用并发集合包中的CopyOnWriteArrayList来自动同步访问。
请注意,内部array
会在每次写入时被复制,顾名思义,因此这可能会对性能产生挑战。
否则,您可能需要更低级别并尝试使用ReentrantReadWriteLock。
答案 3 :(得分:0)
如果您想使用synchronized
,则必须执行类似的操作
synchronized(myList) {
//Do stuff
}
因此,当另一个线程在同步块中时,没有其他线程可以访问该列表。 但请注意deadlocks
这里有一个关于synchronized
的教程
http://tutorials.jenkov.com/java-concurrency/synchronized.html
答案 4 :(得分:0)
只需使用迭代器功能在迭代时删除项目:
private void updateRunning() {
waveTimer();
Iterator<Entity> iterator = entities.iterator();
while(iterator.hasNext()) {
Entity e = iterator.next();
if (e.isMonster() && !block) {
e.toMonster().move();
if (e.toMonster().getHealth() <= 0)
iterator.remove(e);
} else if (e.isTower()) {
e.toTower().setTarget(e.toTower().findTarget());
e.toTower().shoot();
} else if (e.isProjectile()) {
e.toProjectile().update();
}
}
}
这与线程无关,你只是在使用for-each循环迭代它时无法从列表中删除元素。