解决swingworker应用程序中的并发修改异常

时间:2012-10-21 09:27:19

标签: java user-interface collections concurrency swingworker

我正在编写一个应用程序,其中一些模拟在SwingWorker中运行。在此模拟中,一些集保留了在SwingWorker的doInBackground()方法中修改的数据。这些数据需要由GUI显示,但显然这会失败,因为一旦GUI开始访问集合,就会抛出并发修改异常,因为SwingWorker正在修改相同的集合。

如果SwingWorker不必等待GUI完成绘制数据,我将如何分享这些数据?我是否必须复制数据然后发布()那些?这会不会增加很多数据量(有很多数据)?还有其他解决这个问题的方法吗?

这是一些简化的代码:

public class World {
    public Set<Foo> fooSet = new HashSet<Foo>();
}

public class Simulator extends SwingWorker<Void, Void> {
    private World       world;
    private WorldPanel  worldPanel;

    public Simulator(World world, WorldPanel worldPanel) {
        this.world = world;
        this.worldPanel = worldPanel;
    }

    @Override
    protected Void doInBackground() throws Exception {
        while (true) {
            doSomethingWithFooSet() //structurally modifies the set
            publish();
        }
    }

    @Override
    protected void process(List<Void> voidList) {
        worldPanel.repaint();
    }
}

public class WorldPanel extends JPanel {
    private final World             world;

    public WorldPanel(World world) {
        this.world = world;
    }

    @Override
    public void paintComponent(Graphics g) {
        drawWorld() //reads from fooSet in world
    }
}

不要误会我的意思,我理解为什么这不起作用,我只是想知道我应该在这个设计中做些什么才能做我想做的事情:访问我模拟的相同数据修改。 process()是否在EDT上运行?如果是这样,是否可以让process()更新WorldPanel用于绘制数据的世界对象的副本中的集合?

2 个答案:

答案 0 :(得分:2)

您无法同时更新和显示世界对象,因此您有两种方法:按顺序更新和显示,或克隆数据以使更新和显示的数据不同。要实现第一个变体,只需不要使用SwingWorker。在第二个变体中,如果简单克隆整个世界是不可接受的,那么让后台线程不仅要计算世界的新状态,还要修改修改世界图像的命令。 Publish命令然后process更新图片。

答案 1 :(得分:0)

我会在gui中添加一个标志,它是否应显示/访问数据

最初将其设置为false,并且当您的工作人员完成重新加载具有切换标志的访问部分