[英]Java - SwingWorker - problem
我正在開發Java桌面應用程序。 此應用執行同一任務public class MyTask implements Callable<MyObject> {
同時在多個線程中public class MyTask implements Callable<MyObject> {
現在,當用戶單擊“開始”按鈕時,我創建了一個SwingWorker myWorker
並執行了它。
現在,此myWorker
創建MyTask
多個實例,並將其提交給ExecutorService
。
每個MyTask
實例都有一個循環,並在每次迭代時生成中間結果。 現在,我想在每個MyTask
實例生成后立即收集這些中間結果。 然后,從每個MyTask
實例收集這些中間結果之后,我想通過SwingWorker.publish(MyObject)
發布它,以便在EDT上顯示進度。
Q1。 我該如何實施? 我是否也應該使SwingWorker
MyTask
子類而不是Callable
來獲得中間結果,因為我認為Callable
僅返回最終結果。
Q2。 如果是Q1的答案。 是的,那么您能給我一個小例子來說明如何獲取這些中間結果並將其匯總,然后從主SwingWorker
發布它們嗎?
Q3。 如果在這種情況下無法使用SwingWorker
,那么如何實現呢?
看看ExecutorCompletionService <T> 。 它是一個執行程序,提供了take
方法來檢索任何已完成任務的結果。
更新:
擴展SwingWorker
不會做您想要的,因為它專門用於將工作從EDT卸載到后台線程。 您不能使用它將工作從后台線程轉移到其他后台線程。 調用SwingWorker.publish
結果等效於SwingUtilities.invokeLater
。 從后台線程到后台線程,我沒有一種機制可以做相同的事情。 最好的選擇是使用對Queue
的引用來創建MyTask
,並讓SwingWorker.doInBackground
輪詢隊列以獲取中間結果。
A1 + A2 。 Yatendra,您的主SwingWorker
必須是唯一將臨時結果傳遞給EDT
? 如果您的任務也是SwingWorker
實例,則主要工作人員可以將將臨時結果發送回EDT
的責任委托給他們,並且只需照顧TaskWorkers
生命周期。
package threading;
import java.util.LinkedList;
import java.util.List;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
class MainSwingWorker extends SwingWorker<Void, Void> {
private List<TaskWorker> tasks;
public MainSwingWorker() {
tasks = new LinkedList<TaskWorker>();
for(int i=0; i<2; i++)
tasks.add(new TaskWorker(i));
}
@Override
public Void doInBackground() throws Exception {
Test.log("Building tasks.");
for(TaskWorker task : tasks)
launch(task);
Test.log("Waiting 5 secs.");
Thread.sleep(5000);
Test.log("Cancelling tasks");
for(TaskWorker task : tasks )
task.cancel(true);
return null;
}
private void launch(final TaskWorker task) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Test.log("Launching task worker.");
task.execute();
}
});
}
}
class TaskWorker extends SwingWorker<Void, String> {
private int id;
public TaskWorker(int wid) {
id = wid;
}
@Override
public Void doInBackground() throws Exception {
System.out.format("[%s] Starting worker %s\n", Thread.currentThread().getName(), id );
while( !isCancelled() ) {
// ***************************
// your task process code here
// ***************************
publish(String.format("A dummy interim result #%s", id));
Thread.sleep(1000);
}
return null;
}
@Override
public void process(List<String> results) {
// it's pretty obvious, that once this method gets called you can safely
// call the Swing API from EDT among with the interim results
for(String result : results )
Test.log(result);
}
}
public class Test {
public static void log(String msg) {
System.out.format("[%s] %s\n", Thread.currentThread().getName(), msg);
}
public static void main(String[] args) throws Exception {
log("Init.");
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
log("Starting main worker.");
MainSwingWorker worker = new MainSwingWorker();
worker.execute();
}
});
Thread.sleep(7000);
log("Finished.");
}
}
請記住,這只是一個測試,我知道有一些丑陋的Thread.sleep(long)
調用。
[main] Init.
[AWT-EventQueue-0] Starting main worker.
[SwingWorker-pool-1-thread-1] Building tasks.
[SwingWorker-pool-1-thread-1] Waiting 5 secs.
[AWT-EventQueue-0] Launching task worker.
[AWT-EventQueue-0] Launching task worker.
[SwingWorker-pool-1-thread-2] Starting worker 0
[SwingWorker-pool-1-thread-3] Starting worker 1
[AWT-EventQueue-0] A dummy interim result #1
[AWT-EventQueue-0] A dummy interim result #0
[AWT-EventQueue-0] A dummy interim result #0
[AWT-EventQueue-0] A dummy interim result #1
[AWT-EventQueue-0] A dummy interim result #1
[AWT-EventQueue-0] A dummy interim result #0
[AWT-EventQueue-0] A dummy interim result #0
[AWT-EventQueue-0] A dummy interim result #1
[AWT-EventQueue-0] A dummy interim result #0
[AWT-EventQueue-0] A dummy interim result #1
[SwingWorker-pool-1-thread-1] Cancelling tasks
[main] Finished.
A3但是,如果您的項目中需要另一個ExecutorService
來安排您的任務執行,則我將實現類似的發布過程機制,以執行您的Main Swing Worker線程與該Task線程之間的通信。 盡管它似乎是重復的,但您可以使用java.concurrent.ConcurrentQueue
來存儲臨時結果(當它們可用時)?
PS:我幾天前才注意到,但是SwingWorkers周圍有一個令人討厭的錯誤, 阻止其ExecutorService緩存未使用的線程 。
SwingWorker也是未來。 因此,它具有get()方法,該方法完成后可在done()方法內使用該方法來獲取doInBackground()的結果。
因此,構造變得有點像:
SwingWorker<T,P> sw=new SwingWorker<T,P>() {
@Override
public T doInBackground() throws Exception {
T result;
// do stuff here
return result;
}
@Override
public void done() {
try {
T result=get();
// do stuff with result.
}
catch(ExecutionException e) {
Exception fromDoInBackground= (Exception) e.getCause();
// handle exception thrown from doInBackground()
}
catch(InterruptedException i) {
// handle the case in which a SwingWorker was cancelled. typically: do nothing.
}
}
};
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.