在某些对象从列表中删除后,尝试重新绘制对象列表时发生异常。这些项目通过安全的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;
}
}
}
除了图形对象本身,它是操作期间唯一操作的对象。
也许我需要让TPanelObject
从JComponent
继承并将对象添加到面板本身。可能是由于对Graphics对象的访问导致了该异常,因为该异常在重新绘制时不再有效?
答案 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);
}
}