ConcurrentModificationException尽管使用了安全的removeIF

时间:2018-08-20 09:24:10

标签: java list loops jpanel

在某些对象从列表中删除后,尝试重新绘制对象列表时发生异常。这些项目通过安全的Collections.removeIf(...)方法删除。 JPanels repaint()链中的异常发生。

重要方法:

public void run() {
    isRunning = true;
    while (isRunning) {
        try {
            tick();
            repaint();
            Thread.sleep(20);
        } catch (Exception e) {
            isRunning = false;
        }
    }
}

对对象进行滴答和重画分为不同的方法,每个方法都包含循环。

private void tick() {
    for (THead head : heads) {
        head.tick();
    }
    for (TTail tTail : tails) {
        tTail.tick();
    }
    tail.removeIf(o -> !o.isAlive());
}

如果不再设置alive标志,则可以删除尾部。

@Override
public void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2d = (Graphics2D) g;
    for (TTail tTail : tails) {
        tTail.paint(g2d);
    }
    for (THead head : heads) {
        head.paint(g2d);
    }
}

打勾后,所有对象都重新粉刷。这是ConcurrentModificationException发生的位置。我不明白为什么。它全部在同一个线程中运行,并且没有使用任何嵌套循环。要删除项目,我使用removeIf方法,而在删除时不更改对象。

THead和TTail也不继承自任何Swing超类,因此它们各自的paint方法仅使用图形对象执行绘制操作,而不会破坏绘制链。

编辑1: 现在,我已同步访问pos对象,该对象在paint()tick()中都可以访问。

public abstract class TPanelObject {
    private Point pos;
    private Object lock = new Object();

    public Point getPos() {
        synchronized (lock) {
            return pos;
        }
    }

    public void setPos(Point pos) {
        synchronized (lock) {
            this.pos = pos;
        }
    }
}

除了图形对象本身,它是操作期间唯一操作的对象。

也许我需要让TPanelObjectJComponent继承并将对象添加到面板本身。可能是由于对Graphics对象的访问导致了该异常,因为该异常在重新绘制时不再有效?

1 个答案:

答案 0 :(得分:1)

在事件线程¹中运行Repaint / paintComponent等,您的run()方法和tick()方法在不同的线程中运行,因此您确实有多个线程访问同一数据。

不幸的是,您需要同步对tails的访问(否则会使访问共享数据变得安全)。

¹您当然可以从线程中调用它们,但是EDT将在通过repaint()请求时执行绘画。


private void tick() {
    for (THead head : heads) {
        head.tick();
    }
    for (TTail tTail : tails) {
        tTail.tick();
    }
    synchronized(tails) {
        tail.removeIf(o -> !o.isAlive());
    }
}

@Override
public void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2d = (Graphics2D) g;
    synchronized(tails) {
        for (TTail tTail : tails) {
            tTail.paint(g2d);
        }
    }
    for (THead head : heads) {
        head.paint(g2d);
    }
}