您好我一直在尝试学习如何使用SwingWorker更新swing应用程序的GUI。
我的问题是:如果我有2个可以同时运行的swingworkers(每个都是从不同的按钮触发),如何确保在EDT中调用它们的done方法(以更新gui)的顺序相同他们被解雇了?
我的观察和想法: 我试图将他们的doInBackground()方法同步到一个锁,以确保在继续之前必须等待另一个完成他们的任务。问题是我能够(只是几次)看到swingworker_1完成了doInBackground()(当第二个工作人员正在同步块中等待时),但是swingworker_2的done方法能够被EDT调用在swingworker_1完成方法之前,即使swingworker_2完成了之后。我想在doInBackground()返回之前使用发布,这似乎总是有效,但可能是一个不好的做法,因为它似乎用于中间结果而不是最终结果?另一种可能性是在doInBackground()内部使用SwingUtilities.invokeLater在返回之前更新gui,再次恐怕这也可能是一个不好的做法。提前谢谢。
我使用的测试,按下第一个按钮,然后立即按下第二个按钮:
//Code that runs in the first button
SwingWorker<Void, Void> swingworker = new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
synchronized (lock) {
System.out.println("Thread 1");
Thread.sleep(1000);
return null;
}
}
@Override
protected void done() {
System.out.println("Done with thread 1 ");
//update GUI
}
};
swingworker.execute();
//Code that runs in the second button
SwingWorker<Void, Void> swingworker = new SwingWorker<Void, Void>() {
@Override
protected Void doInBackground() throws Exception {
synchronized (lock) {
System.out.println("Thread 2");
return null;
}
}
@Override
protected void done() {
System.out.println("Done with thread 2 ");
//update GUI
}
};
swingworker.execute();
更新:只是为了澄清我并不关心谁首先启动(swingworker_1或swingworker_2),这取决于首先按下哪个按钮。我想要保证的是,如果一个按钮的工作人员是第一个执行的(并因此在doInBackground()方法中工作者同步完成)那么它也应该是第一个在EDT中更新gui的队列。我发现这种情况并不一定会发生,即使工作人员同步,有时后来启动任务的工作人员仍会设法在第一个工作之前更新gui。
答案 0 :(得分:0)
如果您对正在连续运行的工作人员感到满意,那么如果您根据示例代码同步锁定,那么他们就会使用SwingWorker
除doInBackground()
以外的任何其他功能和done()
,您可能更容易使用单个线程执行程序和SwingUtilities.invokeLater(...)
在GUI上显示结果。
这样,您可以保证提交给执行者的内容将按照提交的顺序运行。
如果这对您有用,您可以尝试这样的事情:
final ExecutorService executor = Executors.newSingleThreadExecutor();
// Code that runs in the first button
Runnable worker1 = new Runnable() {
@Override
public void run() {
System.out.println("Thread 1");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace(System.err);
}
SwingUtilities.invokeLater(this::updateGUI);
}
private void updateGUI() {
System.out.println("Done with thread 1");
//update GUI
}
};
executor.execute(worker1);
// Code that runs in the second button
Runnable worker2 = new Runnable() {
@Override
public void run() {
System.out.println("Thread 2");
SwingUtilities.invokeLater(this::updateGUI);
}
private void updateGUI() {
System.out.println("Done with thread 2");
//update GUI
}
};
executor.execute(worker2);