java - 尽管使用了安全removeIF,但出现了ConcurrentModificationException

标签 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 标志,TTails 可能会被删除。

@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 方法,在删除时不会更改对象。

此外,THeaads 和 TTails 并不继承自任何 Swing 父类(super class),因此它们各自的 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;
        }
    }
}

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

也许我需要让TPanelObject继承JComponent并将对象添加到面板本身。异常可能是由访问 Graphics 对象引起的,因为它在重绘时不再有效?

最佳答案

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

关于java - 尽管使用了安全removeIF,但出现了ConcurrentModificationException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51927684/

相关文章:

php - 嵌套循环,打破内循环并继续主循环

java - 从 Hashmap 读取数据 - Android studio、Firebase

java - ProcessBuilder 执行自定义可执行文件

list - LISP - 获取列表的最后一个列表

c# - 使用对象列表填充 UserControl Gridview

c# - 返回列表查看

java - Set<String> 类型的变量返回不可读的输出格式?

java - 从 Spring rest api 返回列表

python - 为什么偶数和奇数不能打印出正确的答案?

javascript - 增量循环