2

如果弹丸超出了我的 JPanel 的边界,我正在使用迭代器从列表中删除它。在使用迭代器之前它不起作用,但是使用迭代器它只要我将方法放入一个ConcurrentModificationException. 代码现在可以工作,并成功地从列表中删除了弹丸,但大约 30% 的时间,catch 命中并导致我的程序卡顿。我不知道为什么它只是偶尔发生,但在我的教授能够看到它的有限时间内,他认为这可能是一个同步问题。

这是运行我的程序的循环:

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()); 
                    }
                }
            }
        }

这由 at 的循环调用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());
}

任何有关为什么会发生这种情况或如何纠正它的见解将不胜感激。

4

2 回答 2

6

Iterator您的循环中有一个 open for(加上额外的Iterator it),并且您在createProjectile. 您需要在 上制作两个块synchronizedshots或者(我的建议)制作副本shots以从以下位置进行绘图:

List<Projectile> shotsToPaint;
synchronized(shots) { shotsToPaint = [`ImmutableList`][1].copyOf(shots); }

并在createProjectile. 根据它对性能的敏感程度,您可以同步整个方法 onshots或 synchronize on shots,检查大小,Projectile在未同步的块中创建新的,然后同步以重新检查列表大小并添加。

于 2013-09-11T22:35:14.063 回答
3

for 循环是问题之一。当您创建这样的循环时:

for (Projectile a : shots) {...}

编译器将其隐式转换为:

for (Iterator<Projectile> i = shots.iterator; i.hasNext();) {
    Projectile a = i.next();
    ...
} 

所以总共有两个迭代器。第一个是在显式调用时创建shots.iterator()的,第二个是由编译器在 for 循环中隐式创建的。

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

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

于 2013-09-11T22:35:52.693 回答