2010-05-08 65 views
2

我正在開發Java桌面應用程序。此應用程序同時在多個線程中執行相同的任務public class MyTask implements Callable<MyObject> {Java - SwingWorker - 問題

現在,當用戶點擊「開始」按鈕時,我創建了SwingWorker myWorker並執行了它。

現在,此myWorker創建了多個MyTask實例並將它們提交到ExecutorService

每個MyTask實例都有一個循環,並在每次迭代時生成一箇中間結果。現在,我希望在生成它們後立即從各個MyTask實例中收集這些中間結果。然後,在收集每個MyTask實例的這些中間結果後,我想通過SwingWorker.publish(MyObject)發佈它,以便在EDT上顯示進度。

Q1。我該如何執行此操作?我應該讓MyTask的子類SwingWorker而不是Callable也得到中間結果,因爲我認爲Callable只返回最終結果。 Q230。

Q2。如果Q1的答案。是的,那麼你能給我一個小例子來展示我如何獲得這些中間結果並聚合它們,然後從主要SwingWorker發佈它們?

Q3。如果在這種情況下我不能使用SwingWorker,那我該如何實現這一點?

+0

當您從每個任務收集中間結果時,是否希望它們都來自相同的迭代?即收集所有迭代1結果,然後迭代2結果? – mdma 2010-05-08 16:31:32

回答

0

看看ExecutorCompletionService<T>。這是一個Executor,它提供了一個take方法來檢索任何完成的任務的結果。

更新:

擴展你想要的東西,因爲它是專門用於卸載從EDT工作提高到一個後臺線程SwingWorker不會做。您不能使用它將工作從後臺線程卸載到其他後臺線程。致電SwingWorker.publish的結果相當於SwingUtilities.invokeLater。我不知道從後臺線程到後臺線程做同樣的事情。您最好的選擇是創建您的MyTask並參照Queue並讓您的SwingWorker.doInBackground輪詢隊列以獲得中間結果。

+0

我想從一個'SwingWorker mainWorker'創建幾個'SwingWorker'。這個'mainWorker'由EDT啓動。從主要員工創建幾個員工的原因是我想要在mainWorker中搜集所有這些員工的中間結果,然後通過這些中間結果發佈。 '發佈(...)'mainWorker'的方法。 – 2010-05-08 19:35:34

-1

SwingWorker也是一個未來。因此,它具有可以在done()方法內部使用的get()方法,以在該方法結束時獲取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. 
    } 
    } 
}; 
+0

@user我請你在回答之前仔細閱讀這個問題......我知道如何使用'SwingWorker'。 :) – 2010-05-08 19:31:46

0

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來安排你的任務的執行是在你的項目的要求,我會實施類似的發佈流程機制,在你的主要的Swing Worker線程和任務線程之間進行通信。雖然它似乎是重複性的,但您可以使用java.concurrent.ConcurrentQueue來存儲臨時結果,因爲它們可用? PS:我剛剛注意到幾天前,但SwingWorkers周圍有一個惱人的bug,prevents its ExecutorService from caching unused threads