我正在使用迭代器从列表中移除射弹,如果它超出了我的JPanel的边界。在使用迭代器之前它不起作用,但只要我将方法放入ConcurrentModificationException
的try-catch中,它就可以使用迭代器。代码现在可以工作,并且成功地从列表中移除了射弹,但是大约30%的时间,捕获命中并导致我的程序中出现断断续续的情况。我不知道为什么它只会偶尔发现,但在有限的时间里,我的教授能够看到它,他认为这可能是同步问题。
这是运行我程序的循环:
private void executeGameLoop()
{
long nextFrameStart = System.nanoTime();
while(panel.getRunning())
{
do
{
panel.repaint();
nextFrameStart += FRAME_PERIOD;
} while(nextFrameStart < System.nanoTime());
long remaining = nextFrameStart - System.nanoTime();
panel.update();
if (remaining > 0)
{
try
{
Thread.sleep(remaining / 1000000);
}
catch(Throwable e)
{
System.out.println(e.getMessage());
}
}
}
}
这由panel.update
的循环调用。它现在处理弹丸的更新:
public void update()
{
randX = (int)((Math.random() * getWidth()) - (int)(Math.random() * getWidth()));
randY = (int)((Math.random() * getHeight()) - (int)(Math.random() * getHeight()));
int sizeX;
int sizeY;
try
{
Iterator<Projectile> it = shots.iterator();
for(Projectile a : shots)
{
if(!a.equals(null))
{
sizeX = a.getDisplayX();
sizeY = a.getDisplayX();
if((!checkCoords((int)a.getX(), (int)a.getY(), sizeX, sizeY)) && a.hasTarget())
{
a = null;
if(it.next().equals(null));
it.remove();
}
else if(a.hasTarget())
{
a.update();
}
}
}
}
catch (ConcurrentModificationException e){ System.out.println(e.getMessage() + " Catch"); }
}
最后两种方法是我创建射弹的机制:
private void createProjectile(int x, int y)
{
total++;
if(shots.size() < shotCount)
{
Projectile temp = new Projectile(randX, randY);
temp.setTarget((x + temp.getSprite().getDisplayImg().getWidth() / 8),
(y - temp.getSprite().getDisplayImg().getHeight() / 8));
temp.setHasTarget(true);
shots.add(temp);
msg("Target: (" + x + ", " + y + ")");
}
}
@Override
public void mouseClicked(MouseEvent e)
{
createProjectile(e.getX(), e.getY());
}
对于为什么会发生这种情况或如何纠正它的任何见解将不胜感激。
答案 0 :(得分:6)
您的Iterator
循环中有一个开放的for
(加上额外的Iterator it
),并且您在createProjectile
中添加了值。你需要在synchronized
上制作两个块shots
,或者(我的推荐)制作一份shots
来制作你的绘图:
List<Projectile> shotsToPaint;
synchronized(shots) { shotsToPaint = [`ImmutableList`][1].copyOf(shots); }
并在createProjectile
中应用适当的同步。根据性能敏感程度,您可以在shots
上同步整个方法,也可以在shots
上同步,检查大小,在非同步块中创建新的Projectile
,然后同步以重新检查列表大小并添加。
答案 1 :(得分:3)
for循环是其中一个问题。当你创建一个这样的循环:
for (Projectile a : shots) {...}
编译器隐式将其转换为:
for (Iterator<Projectile> i = shots.iterator; i.hasNext();) {
Projectile a = i.next();
...
}
所以总共有两个迭代器。第一个是在显式调用shots.iterator()
时创建的,第二个是由编译器在for循环中隐式创建的。
ConcurrentModificationException
的一个原因是当其他人在您迭代它的同时修改列表时。您的教授怀疑是同步问题,因为通常“其他人”在不同的线程中,但在这种情况下,“其他人”是其他迭代器。