0

計算量の多いアプリケーションをコーディングしているときに、SwingWorkerクラスを利用して負荷を複数のCPUコアに分散させようとしました。ただし、このクラスの動作はやや奇妙であることが判明しました。1つのコアのみが使用されているように見えました。

インターネットを検索したところ、このWebで優れた回答が見つかりました(Swingworkerインスタンスが同時に実行されていない、user268396による回答を参照)。これは、問題の原因に加えて、考えられる解決策についても言及しています。

これを回避するためにできることは、ExecutorServiceを使用して、FutureTasksを投稿することです。これらはSwingWorkerAPIの99%を提供します(SwingWorkerはFutureTaskの派生物です)。あなたがしなければならないのは、Executorを適切にセットアップすることだけです。

Javaの初心者なので、これを適切に行う方法が完全にはわかりません。いくつかの初期データをFutureTaskオブジェクトに渡す必要があるだけでなく、SwingWorkerの場合と同様に結果を取得する必要もあります。したがって、サンプルコードをいただければ幸いです。

nvx

====================編集====================

Callableを実装するFutureTaskで説明したシンプルでありながら洗練されたソリューションを実装した後、別の問題が発生しました。を使用ExecutorServiceして個々のスレッドを作成する場合、スレッドの実行が終了した後に特定のコードを実行するにはどうすればよいですか?

オブジェクトのdone()をオーバーライドしようとしましたがFutureTask(以下のコードを参照)、「結果の表示」ビット(またはそのことに関するGUI関連のもの)は、アプリケーションのイベントディスパッチスレッド(EDT)で実行する必要があると思います。したがって、ランナブルをEDTに送信するにはどうすればよいですか?

package multicoretest;

import java.util.concurrent.*;

public class MultiCoreTest {

    static int coresToBeUsed = 4;
    static Future[] futures = new Future[coresToBeUsed];

    public static void main(String[] args) {
        ExecutorService execSvc = Executors.newFixedThreadPool(coresToBeUsed);
        for (int i = 0; i < coresToBeUsed; i++) {
            futures[i] = execSvc.submit(new Worker(i));
        }
        execSvc.shutdown();

        // I do not want to block the thread (so that users can
        // e.g. terminate the computation via GUI)
        //execSvc.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);

    }

    static class Worker implements Callable<String> {

        private final FutureTask<String> futureTask;
        private final int workerIdx;

        public Worker(int idx) {
            workerIdx = idx;
            futureTask = new FutureTask<String>(this) {
                @Override
                protected void done() {
                    Runnable r = new Runnable() {
                        @Override
                        public void run() {
                            showResults(workerIdx);
                        }
                    };

                    r.run(); // Does not work => how do I submit the runnable
                             // to the application's event dispatch thread?

                }
            };
        }

        @Override
        public String call() throws Exception {
            String s = "";
            for (int i = 0; i < 2e4; i++) {
                s += String.valueOf(i) + " ";
            }
            return s;
        }

        final String get() throws InterruptedException, ExecutionException {
            return futureTask.get();
        }

        void showResults(int idx) {
            try {
                System.out.println("Worker " + idx + ":" +
                        (String)futures[idx].get());
            } catch (Exception e) {
                System.err.println(e.getMessage());
            }
        }
    }
}
4

2 に答える 2

2

SwingWorkerクラスを利用して、負荷を複数のCPUコアに分散させようとしました。ただし、このクラスの動作はやや奇妙であることが判明しました。1つのコアのみが使用されているように見えました。

于 2013-02-27T13:10:22.560 に答える
2

いくつかのポイント:

  • FutureTaskを直接使用する必要はめったにありません。CallableまたはRunnableを実装し、インスタンスをExecutorに送信するだけです。
  • 完了時にGUIを更新するには、run()/call()メソッドの最後のステップとしてSwingUtilities.invokeLater()、コードとともにUIを更新します。

を呼び出す代わりに、代わりにSwingWorkerをエグゼキュータに送信することもできます。SwingWorkerexecute()

GUIを更新する前にすべてのスレッドが完了したときにすべての結果を一緒に処理する必要がある場合は、次のことをお勧めします。

  • 各ワーカーに結果をスレッドセーフな共有リストに隠してもらいます
  • リストに結果を追加した最後のワーカーは、後処理作業を行う必要があります
  • 後処理作業を行ったワーカーはSwingUtilities.invokeLater()、最終結果を呼び出して呼び出す必要があります
于 2013-02-28T13:35:14.883 に答える