簡體   English   中英

Java-SwingWorker-問題

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM