SwingWorker でシミュレーションを実行するアプリケーションを作成しています。このシミュレーションでは、一部のセットは SwingWorker の doInBackground() メソッドで変更されたデータを保持します。このデータは GUI で表示する必要がありますが、SwingWorker が同じセットを変更しているため、GUI がセットへのアクセスを開始するとすぐに同時変更例外がスローされるため、これは明らかに失敗します。
SwingWorker が GUI がデータの描画を完了するのを待たずに、このデータを共有するにはどうすればよいでしょうか? データをコピーしてから publish() する必要がありますか? これでかなりデータ量が増えませんか(データ量が多い)?この問題を回避する他の方法はありますか?
簡単なコードを次に示します。
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 で実行されますか? もしそうなら、WorldPanel がデータを描画するために使用するワールド オブジェクトのコピーで process() がセットを更新できるようにすることは可能でしょうか?