計算量の多いアプリケーションをコーディングしているときに、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());
}
}
}
}