Caution
お使いのブラウザはJavaScriptが実行できない状態になっております。
当サイトはWebプログラミングの情報サイトの為、
JavaScriptが実行できない環境では正しいコンテンツが提供出来ません。
JavaScriptが実行可能な状態でご閲覧頂くようお願い申し上げます。
ExecutorService / Executors.newFixedThreadPool()
スレッドプールを使って複数のタスクを効率よく並行実行する仕組みです(Java 5以降)。スレッドの生成・再利用・終了を自動管理するため、『Thread』を直接使うより安全でパフォーマンスに優れています。
構文
import java.util.concurrent.*; // 固定サイズのスレッドプールを作成します。 ExecutorService exec = Executors.newFixedThreadPool(スレッド数); // 単一スレッドのExecutorを作成します。 ExecutorService exec = Executors.newSingleThreadExecutor(); // 必要に応じてスレッドを増減するプールを作成します。 ExecutorService exec = Executors.newCachedThreadPool(); // Runnableタスクを送信します(戻り値なし)。 exec.execute(Runnable task); // Callableタスクを送信して Future を受け取ります(戻り値あり)。 Future<T> future = exec.submit(Callable<T> task); T result = future.get(); // 結果が返るまでブロックします。 // ExecutorServiceをシャットダウンします(必須)。 exec.shutdown(); exec.shutdownNow(); // 実行中のタスクを強制終了します。
主なメソッド一覧
| メソッド | 概要 |
|---|---|
| Executors.newFixedThreadPool(n) | n 個のスレッドからなる固定サイズのプールを作成します。 |
| Executors.newSingleThreadExecutor() | 1つのスレッドでタスクをキューに積んで順に実行します。 |
| Executors.newCachedThreadPool() | 必要に応じてスレッドを生成・再利用します。短命のタスクに適しています。 |
| execute(Runnable) | タスクを非同期で実行します。戻り値はありません。 |
| submit(Callable<T>) | タスクを非同期で実行し、結果を Future<T> で返します。 |
| future.get() | タスクの結果が返るまでブロックして待機します。 |
| shutdown() | 新しいタスクの受け付けを停止し、既存タスクの完了を待って終了します。 |
| shutdownNow() | 実行中のタスクを中断してすぐにシャットダウンします。 |
| awaitTermination(timeout, unit) | 指定時間内に終了するまで待機します。 |
サンプルコード
import java.util.concurrent.*;
// 3スレッドのプールで5つのタスクを並行実行します。
ExecutorService exec = Executors.newFixedThreadPool(3);
for (int i = 1; i <= 5; i++) {
final int taskId = i;
exec.execute(() -> {
System.out.println("タスク" + taskId + " を実行中: " + Thread.currentThread().getName());
try { Thread.sleep(500); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
System.out.println("タスク" + taskId + " が完了しました。");
});
}
// 新しいタスクの受け付けを停止し、残りのタスクが完了するまで待ちます。
exec.shutdown();
// submit() で戻り値を持つタスクを実行します。
ExecutorService exec2 = Executors.newFixedThreadPool(2);
Future<Integer> future1 = exec2.submit(() -> { Thread.sleep(200); return 10 + 20; });
Future<Integer> future2 = exec2.submit(() -> { Thread.sleep(100); return 30 + 40; });
try {
System.out.println("結果1: " + future1.get()); // 『結果1: 30』と出力されます。
System.out.println("結果2: " + future2.get()); // 『結果2: 70』と出力されます。
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
} finally {
exec2.shutdown();
}
概要
スレッドプールを使うことでスレッドの生成コストを削減し、アプリケーションのスループットを向上できます。Executors.newFixedThreadPool() はCPUコア数に合わせたスレッド数を指定するのが一般的で、IO待ちが多い処理ではコア数より多いスレッドを使うのが効果的です。
『shutdown()』を呼ばないとプログラムが終了せずに残り続けることがあります。try-finally を使って必ず呼び出すようにしてください。より高度な非同期処理には『CompletableFuture』を使うことで、複数の非同期タスクを組み合わせて扱えます。
スレッドの基本については『new Thread() / スレッド.start() / Runnable』を参照してください。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。