如何确保两个并发 swingworker 的 done() 方法在 EDT 中以正确的顺序执行?
How to make sure the done() method of two concurrent swingworkers is executed in EDT in the right order?
您好,我一直在尝试学习如何使用 SwingWorker 来更新 swing 应用程序的 GUI。
我的问题是:如果我有 2 个可以同时 运行 的 swingworker(每个都从不同的按钮触发)如何确保在 EDT 中调用他们的 done 方法(更新gui) 他们被解雇的顺序相同吗?
我的观察和想法:
我试图将他们的 doInBackground() 方法同步到一个锁,以确保一个必须等待另一个完成他们的任务才能继续。问题是我已经能够(只是几次)看到 swingworker_1 完成 doInBackground() (而第二个工人正在同步块中等待),但是 swingworker_2 的 done 方法能够在 swingworker_1 的 done 方法之前被 EDT 调用,即使 swingworker_2 在之后完成。我考虑过在 doInBackground() returns 之前使用 publish,这似乎总是有效,但可能是一种不好的做法,因为它似乎用于中间结果而不是最终结果?另一种可能性是在 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。
如果您对工作人员 运行ning 串行表示满意,如果您根据示例代码在锁上同步,并且您没有使用 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);
您好,我一直在尝试学习如何使用 SwingWorker 来更新 swing 应用程序的 GUI。
我的问题是:如果我有 2 个可以同时 运行 的 swingworker(每个都从不同的按钮触发)如何确保在 EDT 中调用他们的 done 方法(更新gui) 他们被解雇的顺序相同吗?
我的观察和想法: 我试图将他们的 doInBackground() 方法同步到一个锁,以确保一个必须等待另一个完成他们的任务才能继续。问题是我已经能够(只是几次)看到 swingworker_1 完成 doInBackground() (而第二个工人正在同步块中等待),但是 swingworker_2 的 done 方法能够在 swingworker_1 的 done 方法之前被 EDT 调用,即使 swingworker_2 在之后完成。我考虑过在 doInBackground() returns 之前使用 publish,这似乎总是有效,但可能是一种不好的做法,因为它似乎用于中间结果而不是最终结果?另一种可能性是在 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。
如果您对工作人员 运行ning 串行表示满意,如果您根据示例代码在锁上同步,并且您没有使用 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);