Java TryCatch ConcurrentModificationException捕获30%的时间

Java TryCatch ConcurrentModificationException捕获30%的时间,java,swing,try-catch,concurrentmodification,Java,Swing,Try Catch,Concurrentmodification,我正在使用迭代器从列表中删除超出JPanel边界的投射物。在使用迭代器之前,它不起作用,但对于迭代器,只要我将该方法放入ConcurrentModificationException的try catch中,它就起作用。代码现在可以工作了,并且成功地从列表中删除了投射物,但是大约30%的时间,捕捉命中并在我的程序中导致口吃。我不知道为什么它只是偶尔捕捉,但在有限的时间内,我的教授能够看到它,他认为这可能是一个同步问题 下面是运行我的程序的循环: private void executeGameLo

我正在使用迭代器从列表中删除超出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()); 
                    }
                }
            }
        }
最后两种方法是我创建投射物的机制:

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());
}
private void(int x,int y)
{
总计++;
if(shots.size()

如果您能深入了解发生这种情况的原因或如何纠正它,我们将不胜感激。

您的
for
循环中有一个开放的
迭代器(加上额外的
迭代器),并且您正在
createSproject
中添加值。您需要在
快照上使两个块
同步
,或者(我的建议)复制
快照
,以便从以下位置进行绘图:

List<Projectile> shotsToPaint;
synchronized(shots) { shotsToPaint = [`ImmutableList`][1].copyOf(shots); }
List shotsToPaint;
已同步(快照){shotsToPaint=[`ImmutableList`][1]。复制(快照);}

并在
中应用适当的同步。根据性能敏感程度的不同,您可以在
shots
上同步整个方法,也可以在
shots
上同步,检查大小,在未同步的块中创建新的
投射物,然后同步以重新检查列表大小并添加。

for循环是问题之一。创建如下循环时:

for (Projectile a : shots) {...}
编译器将其隐式转换为:

for (Iterator<Projectile> i = shots.iterator; i.hasNext();) {
    Projectile a = i.next();
    ...
} 
for(迭代器i=shots.Iterator;i.hasNext();){
射弹a=i.next();
...
} 
所以总共有两个迭代器。第一个是在显式调用shots.iterator()时创建的,第二个是由for循环中的编译器隐式创建的

ConcurrentModificationException
的一个原因是当其他人在您迭代列表的同时修改列表时。您的教授怀疑存在同步问题,因为通常“其他人”位于不同的线程中,但在本例中,“其他人”是另一个迭代器


编辑:正如chrylis所指出的,还有来自不同线程的干扰。

您应该努力防止引起ConcurrentModificationException,而不是捕获它。并且您应该发布堆栈跟踪。FWIW,您有两个主要问题都可能导致
ConcurrentModificationException
s。您需要修复我发现的问题和@dnault发现的问题。感谢您的帮助,我不知道循环中有一个隐含的
迭代器,正如dnault指出的那样。使用此隐含的
迭代器
确实会删除
ConcurrentModificationException
问题。然而,我仍然对任何同步都缺乏经验。你能为我指出一个学习如何在这里应用同步的方向吗?@Caboose我手头没有教程,但基本规则是,你需要仔细检查可能从多个线程使用的任何对象的使用情况;为图形操作保留状态的对象是红旗。总是假设它上的任何两个操作都可能被中断,因此在<代码> CureTealPosile < /代码>中,在检查<代码> siz()/<代码>之后,有人可能修改<代码>投注< /代码>,但在<>代码>添加(TEMP)。如果答案是“否”,则可以通过确保两个方法在同一个锁上同步来强制执行此操作。如果您向我们展示的所有方法都在同一个类中,那么只需在update()和createSprojector()的定义中添加一个“synchronized”关键字即可。有关同步的更多信息,请参见此处:
for (Iterator<Projectile> i = shots.iterator; i.hasNext();) {
    Projectile a = i.next();
    ...
}