Java Academy · レッスン

ExecutorService とスレッドプールの種類

固定、キャッシュ、単一、スケジュール実行のスレッドプールを作成し、それぞれの使いどころを理解します。

レッスン 1/413 ステップ

「ExecutorService とスレッドプールの種類」はCoddyKit上の無料Java Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはJava Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Java Academyコースには全4レッスンが含まれています。

スレッドプールを使う理由

タスクごとに新しいThreadを作成するのはコストがかかります。スレッドの作成と破棄にはオーバーヘッドがあるためです。スレッドプールは一定数のスレッドを再利用して多数のタスクを実行し、オーバーヘッドを削減するとともにリソース消費を制御します。

import java.util.concurrent.*;

// Bad practice: new thread per task
new Thread(() -> System.out.println("task")).start();

// Better: reuse threads from a pool
ExecutorService pool = Executors.newFixedThreadPool(4);
pool.submit(() -> System.out.println("task from pool"));
pool.shutdown();

newFixedThreadPool

正確にN個のスレッドを持つプールを作成します。余分なタスクは、スレッドが利用可能になるまでキューに入ります。必要な並列度が分かっている場合に適しています。

ExecutorService pool = Executors.newFixedThreadPool(4);

for (int i = 0; i < 10; i++) {
    final int taskId = i;
    pool.submit(() -> {
        System.out.println("Task " + taskId + " on " + Thread.currentThread().getName());
    });
}

pool.shutdown();
pool.awaitTermination(10, TimeUnit.SECONDS);

newCachedThreadPool

必要に応じてスレッドを作成し、アイドル状態のスレッドを再利用します。60秒間アイドル状態のスレッドは終了します。短時間で終わるタスクが多数ある場合に適していますが、長時間実行するタスクや無制限のタスクには危険です(メモリを使い果たす可能性があります)。

ExecutorService cached = Executors.newCachedThreadPool();

for (int i = 0; i < 100; i++) {
    cached.submit(() -> {
        // quick task
        double result = Math.sqrt(Math.random());
    });
}
cached.shutdown();

newSingleThreadExecutor

スレッドを正確に1つだけ持つプールです。タスクは送信された順序で逐次実行されます。共有リソースへのアクセスを直列化する場合に適しています。

ExecutorService single = Executors.newSingleThreadExecutor();

single.submit(() -> System.out.println("Task 1"));
single.submit(() -> System.out.println("Task 2"));
single.submit(() -> System.out.println("Task 3"));
// Always prints: Task 1, Task 2, Task 3 (sequential)
single.shutdown();

newScheduledThreadPool

スケジュール実行と繰り返し実行のタスクをサポートします。ポーリング、リトライ、バックグラウンドの保守処理に使用します。

ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2);

// One-shot delay
scheduler.schedule(() -> System.out.println("Delayed!"),
    3, TimeUnit.SECONDS);

// Fixed rate (every 2 seconds)
scheduler.scheduleAtFixedRate(
    () -> System.out.println("Tick"),
    0, 2, TimeUnit.SECONDS);

// Run later: scheduler.shutdown();

VirtualThreadExecutor(Java 21以降)

Java 21では、軽量で作成コストの低い仮想スレッドが導入されました。I/O負荷の高いワークロードにはExecutors.newVirtualThreadPerTaskExecutor()を使用します。

// Java 21+
try (var exec = Executors.newVirtualThreadPerTaskExecutor()) {
    for (int i = 0; i < 10_000; i++) {
        final int id = i;
        exec.submit(() -> {
            Thread.sleep(100); // blocks without tying up OS thread
            System.out.println("vthread " + id);
        });
    }
} // auto-shutdown

適切なプールの選択

ガイドライン:

  • CPUバウンドタスク:NをCPUコア数とした固定プール
  • I/Oバウンドタスク:キャッシュプールまたは仮想スレッド
  • 逐次実行タスク:シングルスレッドエグゼキューター
  • スケジュール実行・繰り返し実行:スケジュールスレッドプール
int cores = Runtime.getRuntime().availableProcessors();
ExecutorService cpuPool = Executors.newFixedThreadPool(cores);
System.out.println("Pool size: " + cores);

カスタムThreadPoolExecutor

細かく制御するには、ThreadPoolExecutorを直接作成します。

ThreadPoolExecutor tpe = new ThreadPoolExecutor(
    2,           // corePoolSize
    10,          // maximumPoolSize
    60L,         // keepAliveTime
    TimeUnit.SECONDS,
    new LinkedBlockingQueue<>(100), // work queue
    Executors.defaultThreadFactory(),
    new ThreadPoolExecutor.CallerRunsPolicy() // rejection policy
);
tpe.submit(() -> System.out.println("Custom pool task"));
tpe.shutdown();

正常なシャットダウン

スレッドを解放するため、必ずExecutorServiceをシャットダウンしてください。shutdown()は新しいタスクの受け付けを停止しますが、キューに入っているタスクは完了させます。shutdownNow()は実行中のタスクのキャンセルを試みます。

ExecutorService pool = Executors.newFixedThreadPool(4);
// ... submit tasks ...

pool.shutdown(); // no new tasks
try {
    if (!pool.awaitTermination(30, TimeUnit.SECONDS)) {
        pool.shutdownNow(); // force cancel
    }
} catch (InterruptedException e) {
    pool.shutdownNow();
    Thread.currentThread().interrupt();
}

AutoCloseableとしてのExecutorService(Java 19以降)

Java 19以降、ExecutorServiceはAutoCloseableを実装しています。自動的にシャットダウンするには、try-with-resourcesを使用します。

// Java 19+ (preview), Java 21 stable
try (ExecutorService pool = Executors.newFixedThreadPool(4)) {
    pool.submit(() -> System.out.println("task"));
} // pool.close() called: waits for tasks then shuts down

拒否ポリシー

プールが飽和状態(すべてのスレッドが使用中で、キューも満杯)になると、拒否ポリシーが超過したタスクを処理します。

  • AbortPolicy(デフォルト):RejectedExecutionExceptionをスローします
  • CallerRunsPolicy:呼び出し元のスレッドでタスクを実行します
  • DiscardPolicy:タスクを通知なしに破棄します
  • DiscardOldestPolicy:キュー内で最も古いタスクを破棄します

確認問題

重い計算を実行するCPUバウンドタスクがあります。固定スレッドプールには何個のスレッドを用意すべきですか?

復習:ExecutorServiceとスレッドプール

重要なポイント:

  • 固定プール:スレッド数Nが固定され、余分なタスクはキューに入ります
  • キャッシュプール:必要に応じて拡張し、アイドル状態のスレッドは60秒後に破棄されます
  • シングルスレッド:逐次実行の順序が保証されます
  • スケジュールプール:遅延タスクと繰り返しタスクに使用します
  • 必ずshutdown()を呼び出し、正常に終了するにはawaitTermination()を使用します
無料で開始

AI チューターと学ぶ Java — 無料

ブラウザでリアルコードを書いて実行し、24/7 の AI チューターから瞬時にサポートを受け、ウェブまたはアプリで続きから学習できます。

コース
104
レッスン
374

よくある質問

「ExecutorService とスレッドプールの種類」レッスンは無料ですか?

はい。「ExecutorService とスレッドプールの種類」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Java Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Java Academyコースには全4レッスンが含まれています。

「ExecutorService とスレッドプールの種類」で何を学びますか?

固定、キャッシュ、単一、スケジュール実行のスレッドプールを作成し、それぞれの使いどころを理解します。 ブラウザで直接実行するハンズオンコードでJava Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Java Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのJava Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。

「ExecutorService とスレッドプールの種類」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このJava Academyレッスンでコードを書いて実行できますか?

はい。すべてのJava Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. ExecutorService とスレッドプールの種類
  2. タスクの送信:Runnable と Callable
  3. Future とエラー処理
  4. 定期タスクのための ScheduledExecutorService
← Java Academyに戻る