Java ExecutorService クラス

ExecutorService は Java 並行プログラミングにおける中核インターフェースであり、それはjava.util.concurrentパッケージに属します。

ExecutorService は、より高度なスレッド管理方式を提供し、開発者が手動でスレッドを作成・管理することなく、非同期タスクを効率的に実行できるようにします。

ExecutorService の主な役割は次のとおりです:

  • スレッドプール管理:スレッドのライフサイクルを自動管理し、スレッドの作成と破棄のオーバーヘッドを削減します。
  • タスクスケジューリング:タスクの送信をサポートし、Runnable 或 Callableタスクの実行状態を追跡するためのFutureオブジェクトを返します。
  • リソース最適化:スレッドプールでスレッドを再利用し、システムパフォーマンスを向上させます。

ExecutorService のコアメソッド

ExecutorService は、タスクの実行を送信・管理・制御するためのさまざまなメソッドを提供します。以下は主要なメソッドです:

submit()

1つのタスク(Runnable 或 Callable)を送信し、Futureオブジェクトを返します。これにより、タスクの完了を確認したり戻り値を取得したりできます。

例

ExecutorService executor = Executors.newFixedThreadPool(2);
Future<?> future = executor.submit(() -> {
    System.out.println("Task is running");
});

execute()

タスクの送信のみに使用され、Runnable結果は返しません。

例

executor.execute(() -> {
    System.out.println("Task executed");
});

shutdown()

スレッドプールをグレースフルにシャットダウンし、新しいタスクは受け付けませんが、送信済みのタスクが完了するまで待機します。

例

executor.shutdown();

shutdownNow()

スレッドプールを直ちにシャットダウンし、実行中のすべてのタスクの中断を試み、未実行のタスクのリストを返します。

例

List<Runnable> notExecutedTasks = executor.shutdownNow();

awaitTermination()

すべてのタスクが完了するかタイムアウトするまで、スレッドプールのシャットダウンを待機します。

例

executor.awaitTermination(10, TimeUnit.SECONDS);

ExecutorService の作成方法

Java は、さまざまなタイプのスレッドプールを作成するためのExecutorsユーティリティクラスを提供しています:

newFixedThreadPool(int nThreads)

固定サイズのスレッドプールを作成します。負荷が安定しているタスクに適しています。

例

ExecutorService fixedThreadPool = Executors.newFixedThreadPool(4);

newCachedThreadPool()

キャッシュ型スレッドプールを作成します。短命の非同期タスクに適しています。

例

ExecutorService cachedThreadPool = Executors.newCachedThreadPool();

newSingleThreadExecutor()

単一スレッドのスレッドプールを作成します。順次実行されるタスクに適しています。

例

ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();

newScheduledThreadPool(int corePoolSize)

定時実行または周期的なタスクをサポートするスレッドプールを作成します。

例

ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(2);

使用例

Runnable タスクを送信する

例

ExecutorService executor = Executors.newFixedThreadPool(2);

executor.submit(() -> {
    System.out.println("Task 1 running");
});

executor.submit(() -> {
    System.out.println("Task 2 running");
});

executor.shutdown();

Callable タスクを送信して結果を取得する

例

ExecutorService executor = Executors.newFixedThreadPool(2);

Future<String> future = executor.submit(() -> {
    Thread.sleep(1000);
    return "Task completed";
});

try {
    String result = future.get(); // タスクが完了するまでブロックする
    System.out.println(result);
} catch (Exception e) {
    e.printStackTrace();
}

executor.shutdown();

ベストプラクティス

  1. スレッドプールのサイズを適切に設定する:

    • CPU 集約型タスク:线程数 = CPU 核心数 + 1
    • I/O 集約型タスク:线程数 = CPU 核心数 * 2
  2. メモリリークを避ける:

    • 必ず呼び出して、shutdown() 或 shutdownNow()スレッドプールをシャットダウンしてください。
  3. 例外処理:

    • を使用してtry-catchタスク内の例外をキャッチし、スレッドが予期せず終了するのを防ぎます。
  4. を使用してFutureタスクを管理します。:

    • を通じてFuture.get()タスクの結果を取得したり、タスクの状態を確認したりします。
その他の拡張