更新精灵图像时出现 ConcurrentModificationException
ConcurrentModificationException when updating sprite images
我在 运行 玩我的游戏时不断收到 ConcurrentModificationException,该游戏利用多线程创建新精灵并移动它们。主要问题似乎发生在 "Fireballs" 的创建 and/or 运动中。
通过注释掉 createNewFireballs 方法,我已经能够 运行 我的程序成功,没有出现任何异常。但是,每当我使用 createNewFireballs 方法时,每当我调用更新 Fireball Sprite 图像的函数时通常会出现错误(并且不会发生在任何其他类型的 Sprite 上。)我想知道是否有人可以帮助我找到问题的根源并可能解决问题。
public synchronized void createNewFireball() {
new Thread(new Runnable() {
public void run() {
while (gameNotPaused && hero.isNotDead()) {
fireball = new Fireball(dragon.getX(), dragon.getY());
fireballs.add(fireball);
try
{
Thread.sleep(100); //Waits for .1 second
}
catch(InterruptedException e)
{
e.printStackTrace();
Thread.currentThread().interrupt();
}
}
}
}).start();
}
//The problem commonly occurs in the update method,
//specifically the line "FireballIter.next().updateImage(g);"
public synchronized void update(Graphics g) {
Iterator<Sprite> FireballIter = fireballs.iterator();
Iterator<Sprite> arrowIter = arrows.iterator();
while (arrowIter.hasNext()) {
arrowIter.next().updateImage(g);
}
Iterator<Sprite> iterator = sprites.iterator();
while (iterator.hasNext()) {
iterator.next().updateImage(g);
}
while (FireballIter.hasNext()) {
FireballIter.next().updateImage(g);
}
}
//Although sometimes it occurs as a result of updateScene, which is
//called in another method which moves all the "projectile" sprites
public synchronized void updateScene(int width, int height) {
Iterator<Sprite> arrowIter = arrows.iterator();
while(arrowIter.hasNext()) {
Sprite spriteObject = arrowIter.next();
((Arrow) spriteObject).updateState();
if (spriteObject.overlaps(dragon, 350, 350)) {
dragon.arrowHit();
System.out.printf("Dragon was hit at %d, %d%n, while arrow was at %d,%d%n", dragon.getX(), dragon.getY(), spriteObject.getX(), spriteObject.getY());
arrowIter.remove();
}
}
Iterator<Sprite> fireballIter = fireballs.iterator();
while(fireballIter.hasNext()) {
Sprite spriteObject = fireballIter.next();
((Fireball) spriteObject).updateState();
}
}
@Override
public synchronized void run() {
while (model.getGameNotPaused()) {
model.updateScene(view.getWidth(), view.getHeight());
view.repaint();
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
JOptionPane.showMessageDialog(null, "Press R to resume game.");
}
}
}
使 createNewFireball
同步没有任何用处:同步仅适用于该方法的执行,而不适用于线程执行的可运行对象(这很好,因为否则 none 其他方法将能够执行到 while 循环结束)。
将 fireballs.add
放入 synchronized
块中,注意确保同步正确:
- 如果您只是使用
synchronized (this)
,您将在 Runnable
上同步。
- 而是使用
synchronized (TheContainingClass.this)
(其中 TheContainingClass
是包含这些方法的 class 的名称)。
假设你的火球是一个 ArrayList<Fireball>,
你也可以考虑将它切换到 CopyOnWriteArrayList ,ArrayList
的线程安全变体
我在 运行 玩我的游戏时不断收到 ConcurrentModificationException,该游戏利用多线程创建新精灵并移动它们。主要问题似乎发生在 "Fireballs" 的创建 and/or 运动中。
通过注释掉 createNewFireballs 方法,我已经能够 运行 我的程序成功,没有出现任何异常。但是,每当我使用 createNewFireballs 方法时,每当我调用更新 Fireball Sprite 图像的函数时通常会出现错误(并且不会发生在任何其他类型的 Sprite 上。)我想知道是否有人可以帮助我找到问题的根源并可能解决问题。
public synchronized void createNewFireball() {
new Thread(new Runnable() {
public void run() {
while (gameNotPaused && hero.isNotDead()) {
fireball = new Fireball(dragon.getX(), dragon.getY());
fireballs.add(fireball);
try
{
Thread.sleep(100); //Waits for .1 second
}
catch(InterruptedException e)
{
e.printStackTrace();
Thread.currentThread().interrupt();
}
}
}
}).start();
}
//The problem commonly occurs in the update method,
//specifically the line "FireballIter.next().updateImage(g);"
public synchronized void update(Graphics g) {
Iterator<Sprite> FireballIter = fireballs.iterator();
Iterator<Sprite> arrowIter = arrows.iterator();
while (arrowIter.hasNext()) {
arrowIter.next().updateImage(g);
}
Iterator<Sprite> iterator = sprites.iterator();
while (iterator.hasNext()) {
iterator.next().updateImage(g);
}
while (FireballIter.hasNext()) {
FireballIter.next().updateImage(g);
}
}
//Although sometimes it occurs as a result of updateScene, which is
//called in another method which moves all the "projectile" sprites
public synchronized void updateScene(int width, int height) {
Iterator<Sprite> arrowIter = arrows.iterator();
while(arrowIter.hasNext()) {
Sprite spriteObject = arrowIter.next();
((Arrow) spriteObject).updateState();
if (spriteObject.overlaps(dragon, 350, 350)) {
dragon.arrowHit();
System.out.printf("Dragon was hit at %d, %d%n, while arrow was at %d,%d%n", dragon.getX(), dragon.getY(), spriteObject.getX(), spriteObject.getY());
arrowIter.remove();
}
}
Iterator<Sprite> fireballIter = fireballs.iterator();
while(fireballIter.hasNext()) {
Sprite spriteObject = fireballIter.next();
((Fireball) spriteObject).updateState();
}
}
@Override
public synchronized void run() {
while (model.getGameNotPaused()) {
model.updateScene(view.getWidth(), view.getHeight());
view.repaint();
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
JOptionPane.showMessageDialog(null, "Press R to resume game.");
}
}
}
使 createNewFireball
同步没有任何用处:同步仅适用于该方法的执行,而不适用于线程执行的可运行对象(这很好,因为否则 none 其他方法将能够执行到 while 循环结束)。
将 fireballs.add
放入 synchronized
块中,注意确保同步正确:
- 如果您只是使用
synchronized (this)
,您将在Runnable
上同步。 - 而是使用
synchronized (TheContainingClass.this)
(其中TheContainingClass
是包含这些方法的 class 的名称)。
假设你的火球是一个 ArrayList<Fireball>,
你也可以考虑将它切换到 CopyOnWriteArrayList ,ArrayList