2

I am developing a Java Desktop Application. This app executes the same task public class MyTask implements Callable<MyObject> { in multiple thread simultaneously.

Now, when a user clicks on a "start" button, I have created a SwingWorker myWorker and have executed it.

Now, this myWorker creates multiple instances of MyTask and submits them to an ExecutorService.

Each MyTask instance has a loop and generates an intermediate result at every iteration. Now, I want to collect these intermediate results from each MyTask instances as soon as they are generated. Then after collecting these intermediate results from every MyTask instance, I want to publish it through SwingWorker.publish(MyObject) so that the progress is shown on the EDT.

Q1. How can I implement this? Should I make MyTask subclass of SwingWorker instead of Callable to get intermediate results also, because I think that Callable only returns final result.

Q2. If the answer of Q1. is yes, then can you give me a small example to show how can I get those intermediate results and aggregate them and then publish them from main SwingWorker?

Q3. If I can't use SwingWorker in this situation, then how can I implement this?

4

3 に答える 3

0

ExecutorCompletionService<T>を見てください。takeこれは、完了したタスクの結果を取得するためのメソッドを提供するエグゼキューターです。

アップデート:

拡張SwingWorkerは、EDTからバックグラウンドスレッドに作業をオフロードすることを特に目的としているため、期待どおりには機能しません。これを使用して、バックグラウンドスレッドから他のバックグラウンドスレッドに作業をオフロードすることはできません。を呼び出すとSwingWorker.publish、と同等になりSwingUtilities.invokeLaterます。バックグラウンドスレッドからバックグラウンドスレッドまで同じことを行うために私が知っているメカニズムはありません。最善の策はMyTask、を参照してを作成し、Queue中間SwingWorker.doInBackground結果のキューをポーリングすることです。

于 2010-05-08T14:51:03.127 に答える
0

A1+A2 . Yatendra、あなたの MainSwingWorkerだけが中間結果を に渡す必要があります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、プロジェクトでタスクの実行をスケジュールするために別のものが必要な場合は、同様のパブリッシュ プロセス メカニズムを実装して、メイン スイング ワーカー スレッドとそのタスク スレッド間の通信を実行します。繰り返しのようですが、java.concurrent.ConcurrentQueue利用可能になったときに中間結果を保存するために を使用できますか?

PS: 数日前に気づいたのですが、SwingWorkers の周りに ExecutorService が未使用のスレッドをキャッシュできないという厄介なバグがあります。

于 2010-06-27T15:50:11.983 に答える
-1

SwingWorker も Future です。そのため、メソッドが終了したときに doInBackground() の結果を取得するために done() メソッド内で使用できる get() メソッドがあります。

したがって、構造は次のようになります。

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.
    }
  }
};
于 2010-05-08T15:24:24.987 に答える