我正在编写一个应用程序,其中一些模拟在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用于绘制数据的世界对象的副本中的集合?
答案 0 :(得分:2)
您无法同时更新和显示世界对象,因此您有两种方法:按顺序更新和显示,或克隆数据以使更新和显示的数据不同。要实现第一个变体,只需不要使用SwingWorker。在第二个变体中,如果简单克隆整个世界是不可接受的,那么让后台线程不仅要计算世界的新状态,还要修改修改世界图像的命令。 Publish
命令然后process
更新图片。
答案 1 :(得分:0)
我会在gui中添加一个标志,它是否应显示/访问数据
最初将其设置为false,并且当您的工作人员完成重新加载具有切换标志的访问部分
时