ホームページ >Java >&#&チュートリアル >ExecutorService のシャットダウンをマスターする: ThreadPool の終了を追跡する

ExecutorService のシャットダウンをマスターする: ThreadPool の終了を追跡する

Patricia Arquette
Patricia Arquetteオリジナル
2025-01-05 01:50:38898ブラウズ

Mastering ExecutorService Shutdown: Tracking ThreadPool Termination

いくつかのタスクを実行するとします。単一のスレッドで実行すると結果が得られるまでにかなりの時間がかかる可能性があるため、信頼性の高い ExecutorService を使用して複数のスレッドで処理することにします。

これがサンプルです:

public static void main(String[] args) {
    ExecutorService executorService = Executors.newFixedThreadPool(5);
    for (int i = 0; i < 5; i++) {
        int temp = i;
        executorService.submit(() -> {
            task(temp);
        });
    }
    executorService.shutdown();
    System.out.println("ExecutorService is shutdown");
}

private static void task(int temp) {
    try {
        TimeUnit.SECONDS.sleep(1L);
        System.out.println("Task " + temp + " completed");
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
}

もちろん、いつものように、タスク実行の原型として「スリープ」を使用せずにスレッドの例を完成させることはできません。

出力します

ExecutorService is shutdown
Task 1 completed
Task 2 completed
Task 0 completed
Task 4 completed
Task 3 completed

次に、タスクの無限のキューがあり、その数はわかりません。おそらく、それらは動的に追加されるデータベース内のエントリの数によって決定されます。

たとえば、銀行では、1 日を通して多数の取引を処理する必要があります。トランザクションの終了時間は午後 5 時となり、それを超えると追加のタスクは受け付けられなくなります。

ただし、タスクの数は有限であり、ある時点で終了することはわかっています。

すべてのタスクが完了した時点をどのようにして知ることができますか?

上記のコード スニペットに気付いた場合は、ExecutorService.shutdown() によってメイン スレッドがすぐに終了できるようになりますが、バックグラウンド スレッドは依然として受け入れられたタスクを完了まで処理します。いつ完了の通知を受け取る方法はありますか?

いくつかの解決策が思い浮かびます:

  1. CountDownLatch を使用してタスクをカウントします。ただし、タスクの数がわからないため、これを使用するのは非現実的です。
  2. ExecutorService.awaitTermination() を使用します。ただし、ここでの時間はまだ未定です。非常に自由度の高い ExecutorService.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS) などを使用できます。しかし、これもまたブロック呼び出しです。

これを解決するより良い方法はありますか?

Java は、これを回避するための、比較的知られていないより良い方法を提供します。ここでの「コツ」は、Executors.newFixedThreadPool が本質的には事前定義された値を持つ ThreadPoolExecutor であることを知ることです。 Executors.newFixedThreadPool.
の実装を確認してみましょう。

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

ここで ThreadPoolExecutor のドキュメントを読むことを強くお勧めします。 ExecutorService は、ThreadPoolExecutor の便利なラッパーです。

...プログラマは、より便利な Executors ファクトリ メソッド Executors.newCachedThreadPool() (自動スレッド再利用機能を備えた無制限のスレッド プール)、Executors.newFixedThreadPool(int) (固定サイズのスレッド プール)、および Executors.newSingleThreadExecutor( ) (単一のバックグラウンド スレッド)、最も一般的な使用シナリオの設定を事前に構成します。

問題の解決に役立つセクションは次のとおりです。

フックメソッド

このクラスは、各タスクの実行の前後に呼び出される、保護されたオーバーライド可能な beforeExecute(Thread, Runnable) メソッドと afterExecute(Runnable, Throwable) メソッドを提供します。これらは実行環境を操作するために使用できます。たとえば、ThreadLocals の再初期化、統計の収集、ログ エントリの追加などです。さらに、Executor が完全に終了した後に実行する必要がある特別な処理を実行するために、メソッドterminated() をオーバーライドできます。

終了したメソッドを使用して同じことを通知できます。しかし、それをどのように使用するのでしょうか?

public static void main(String[] args) {
    ExecutorService executorService = Executors.newFixedThreadPool(5);
    for (int i = 0; i < 5; i++) {
        int temp = i;
        executorService.submit(() -> {
            task(temp);
        });
    }
    executorService.shutdown();
    System.out.println("ExecutorService is shutdown");
}

private static void task(int temp) {
    try {
        TimeUnit.SECONDS.sleep(1L);
        System.out.println("Task " + temp + " completed");
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
}

(私のように) 匿名クラスを好まない場合は、いつでも ThreadPoolExecutor を自分で拡張してカスタム クラスを作成できます。

ExecutorService is shutdown
Task 1 completed
Task 2 completed
Task 0 completed
Task 4 completed
Task 3 completed

期待どおりに動作するかどうかを確認するための出力を次に示します。

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

あなたが使用している他の比較的知られていないスニペットは何ですか?コメント欄でお知らせください!

以上がExecutorService のシャットダウンをマスターする: ThreadPool の終了を追跡するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。