Java の ExecutorService の使い方について
このページでは、Java の ExecutorService
を活用する方法について詳しく解説します。各セクションにジャンプするリンクを用意しました。
ExecutorServiceとは
ExecutorService
は、Java でスレッドプールを利用するためのインターフェースです。複数のタスクを効率よく並列処理するために、スレッドプールを使用してリソースを再利用します。
主な特徴:
- スレッドを手動で管理する手間を軽減
- スレッドのライフサイクルを自動的に制御
- 複数のタスクを効率的に処理
ExecutorServiceの作成方法
ExecutorService は Executors
クラスを使用して作成します。以下は一般的な作成方法です。
固定スレッドプール
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class FixedThreadPoolExample {
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(3);
Runnable task = () -> {
System.out.println("Task executed by " + Thread.currentThread().getName());
};
for (int i = 0; i < 5; i++) {
executor.submit(task);
}
executor.shutdown();
}
}
固定スレッドプールは指定した数のスレッドを再利用します。
キャッシュスレッドプール
ExecutorService executor = Executors.newCachedThreadPool();
キャッシュスレッドプールは必要に応じてスレッドを生成し、アイドル状態のスレッドを再利用します。
シングルスレッドエグゼキュータ
ExecutorService executor = Executors.newSingleThreadExecutor();
シングルスレッドエグゼキュータは、1つのスレッドでタスクを逐次実行します。
submitメソッドとexecuteメソッドの違い
submit
と execute
はタスクを実行するために使用されますが、動作にいくつかの違いがあります。
execute
Runnable を引数に取り、戻り値はありません。
executor.execute(() -> System.out.println("Task executed!"));
submit
Callable または Runnable を引数に取り、戻り値として Future オブジェクトを返します。
Future<String> result = executor.submit(() -> {
return "Task completed!";
});
System.out.println(result.get()); // "Task completed!"
タスクの管理
ExecutorService
ではタスクの管理が容易です。
複数のタスクを並列実行
List<Callable<String>> tasks = Arrays.asList(
() -> "Task 1",
() -> "Task 2",
() -> "Task 3"
);
List<Future<String>> results = executor.invokeAll(tasks);
for (Future<String> result : results) {
System.out.println(result.get());
}
最初に完了したタスクの結果を取得
String result = executor.invokeAny(tasks);
System.out.println(result); // 最初に完了したタスクの結果
ExecutorServiceのシャットダウン
ExecutorService を使用後は必ずシャットダウンしてください。
シャットダウンの方法
executor.shutdown(); // 新しいタスクの受け付けを停止
if (!executor.awaitTermination(1, TimeUnit.MINUTES)) {
executor.shutdownNow(); // 強制終了
}
応用例
スケジュールタスクの実行
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
scheduler.schedule(() -> System.out.println("Task executed after delay"), 5, TimeUnit.SECONDS);
scheduler.shutdown();
カスタムスレッドプール
ExecutorService customExecutor = new ThreadPoolExecutor(
2, 4, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>()
);
カスタムスレッドプールを使用すると、柔軟な設定が可能です。
以上で ExecutorService
の基本的および応用的な使い方の解説は終わりです。