ExecutorServiceでshutdown()を呼び出す理由


84

私は過去数時間でそれについてかなり読んでいた、と私は単に何らかの理由(見ることができない正当なコールする理由)shutdown()上をExecutorService我々が使用されていない別のエグゼキュータのサービスのでかいアプリケーションストア、何十と数十を持っていない限り、長い間。

(私が収集したものから)シャットダウンが行う唯一のことは、それが行われた後、通常のスレッドが行うことを行うことです。通常のスレッドがRunnable(またはCallable)のrunメソッドを終了すると、ガベージコレクションに渡されて収集されます。エグゼキュータサービスを使用すると、スレッドは単に保留になり、ガベージコレクション用にチェックされません。そのためにはシャットダウンが必要です。

質問に戻りましょう。ExecutorService非常に頻繁に、またはいくつかのタスクを送信した直後にシャットダウンを呼び出す理由はありますか?誰かがそれをしているケースを残し、その直後にawaitTermination()これが検証されたときに電話をかけたいと思います。それを行っExecutorServiceたら、同じことをするために、新しいものをもう一度作り直す必要があります。ExecutorServiceスレッドを再利用するための全体的なアイデアではありませんか?では、なぜExecutorServiceそんなに早く破壊するのですか?

単純に作成するExecutorService(または必要な数に応じて結合する)のは合理的な方法ではありません。アプリケーションの実行中に、タスクが発生したらタスクを渡し、アプリケーションの終了またはその他の重要な段階でそれらのエグゼキュータをシャットダウンします。 ?

ExecutorServicesを使用して多くの非同期コードを作成する経験豊富なコーダーからの回答をお願いします。

2番目の質問、Androidプラットフォームを扱う少し小さい。毎回エグゼキュータをシャットダウンするのは最善ではないと言う人がいて、Androidでプログラムしている場合、さまざまなイベントを処理するときに、これらのシャットダウンをどのように処理するか(具体的には、実行するとき)を教えてください。アプリケーションのライフサイクル。

CommonsWareのコメントのため、私は投稿を中立にしました。私はそれについて議論することに本当に興味がなく、それがそこにつながっているようです。経験豊富な開発者が経験を共有してくれるのであれば、ここで私がここで尋ねたことについて学ぶことにのみ興味があります。ありがとう。


3
「サンプルコードを何度も目にしますが、タスクを送信または実行した直後に、shutdown()が呼び出されます」-ハイパーリンクを使用して、主張の証拠を提供してください。個人的に、私はあなたが述べていることを行う「サンプルコード」を見たことがありません。あなたが何かを誤解している可能性があり、あなたが調べている「サンプルコード」を知っている場合にのみ、それを指摘することができます。
CommonsWare 2013

4
こんにちはCommonsWare。まず第一に、私はあなたの(またはそう思われる)攻撃的な口調を私に向けて見ますが、それはここでは検証されていないと思います。私は人々を否定的な方法で描写しようとしていませんでした。あなたの引用に関しては、私は主にThinking In Java IVエディション、マルチタスクの部分について話していました。ブルース・エッケルの例でその多くの例を見つけることができます。それらはほとんど単純ですが、ブルースが私に与えた印象は、シャットダウンを頻繁に使用することでした。とにかく、あなたは私の投稿の主要部分ではない何かに焦点を合わせました。私はそれらの部分を削除しました。なぜなら、私はそれについて議論したくないからです。
ルーカス

1
hay @CommonsWare in Thinking in java book by Bruce Eckel..in concurrency / Executor page 804第4版、彼は単純なアプリでタスクを送信または実行した直後に常にshutdown()メソッドを使用して、ルーカスが言ったようにExecutorがどのように機能するかを示しています
エラー

2
これが古い投稿であることは知っていますが、OPの質問はまだ有効であると思います。また、「execute()の直後にshutdown()呼び出しがある」という多くのサンプルコードに出くわしました。tutorials.jenkov.com/java-util-concurrent/executorservice.html(「javaexecutorserviceexample」をグーグルで
検索

ありがとう、私はこれらの「サンプルコード」で提起されたのと同じ質問をしました。 journaldev.com/2340/...
Gregordy

回答:


57

このshutdown()メソッドは1つのことを行います。それは、クライアントがエグゼキュータサービスにさらに多くの作業を送信できないようにすることです。これは、他のアクションが実行されない限り、既存のすべてのタスクが引き続き実行されて完了することを意味します。これは、スケジュールされたタスクにも当てはまります。たとえば、ScheduledExecutorServiceの場合:スケジュールされたタスクの新しいインスタンスは実行されません。これは、さまざまなシナリオで役立ちます。

N個のタスクを実行するエグゼキュータサービスを持つコンソールアプリケーションがあると仮定します。ユーザーがCTRL-Cを押すと、アプリケーションがおそらく正常に終了することが期待されます。優雅とはどういう意味ですか?アプリケーションがエグゼキュータサービスにそれ以上のタスクを送信できないようにすると同時に、既存のN個のタスクが完了するのを待ちたい場合があります。最後の手段としてシャットダウンフックを使用してこれを実現できます。

final ExecutorService service = ... // get it somewhere

Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("Performing some shutdown cleanup...");
        service.shutdown();
        while (true) {
            try {
                System.out.println("Waiting for the service to terminate...");
                if (service.awaitTermination(5, TimeUnit.SECONDS)) {
                    break;
                }
            } catch (InterruptedException e) {
            }
        }
        System.out.println("Done cleaning");
    }
}));

このフックはサービスをシャットダウンします。これにより、アプリケーションは新しいタスクを送信できなくなり、既存のすべてのタスクが完了するのを待ってからJVMをシャットダウンします。待機終了は5秒間ブロックされ、サービスがシャットダウンされるとtrueを返します。これはループで実行されるため、サービスは最終的にシャットダウンされます。InterruptedExceptionは毎回飲み込まれます。これは、アプリケーション全体で再利用されるエグゼキュータサービスをシャットダウンするための最良の方法です。

このコードは完璧ではありません。タスクが最終的に終了することを完全に確信していない限り、指定されたタイムアウトを待ってから終了し、実行中のスレッドを放棄することをお勧めします。この場合shutdownNow()、実行中のスレッドを中断する最後の試みでタイムアウト後に呼び出すことも理にかなっています(shutdownNow()実行を待機しているタスクのリストも表示されます)。タスクが中断に応答するように設計されている場合、これは正常に機能します。

もう1つの興味深いシナリオは、定期的なタスクを実行するScheduledExecutorServiceがある場合です。定期的なタスクのチェーンを停止する唯一の方法は、を呼び出すことshutdown()です。

編集:一般的な場合に上記のようにシャットダウンフックを使用することはお勧めしません。エラーが発生しやすい可能性があり、最後の手段にすぎないことを付け加えておきます。さらに、多数のシャットダウンフックが登録されている場合、それらが実行される順序は定義されていないため、望ましくない場合があります。私はむしろ、アプリケーションを呼び出す明示的に必要があるだろうshutdown()InterruptedException


ジョバンニの返答が遅れてすみません、そしてそのところでありがとう。はい、私はエグゼキュータがどのように機能するかを知っています。それは私の質問で説明しようとしました。シャットダウンはあなたが言ったことを実行し、ガベージコレクターがそれらのデッドスレッドを収集し、事実上ExecutorServiceインスタンスを収集できるようにします。私の質問は具体的でした。ExecutorServiceで何かを送信/実行した直後に、常に「shutdown()」を呼び出す理由はありますか?質問の2番目の部分は、厳密にAndroidアーキテクチャに関連しています。前の答えが「いいえ」の場合、およびの間にシャットダウンを呼び出すタイミング。ライフサイクル。
ルーカス

3
常にshutdown()を呼び出す理由はありません。実際、エグゼキュータサービスを再利用できなくなるため、これは絶対に間違っている可能性があります。サービスのライフサイクルの終わりにそれを呼び出す理由は、あなたが気づいたようにスレッドが最終的にガベージコレクションされることができるようにするためです。そうしないと、それらのスレッドはアイドル状態であってもJVMを存続させます。
ジョバンニボッタ

「shutdown()を常に呼び出す理由はありません。実際、エグゼキュータサービスを再利用できなくなるため、これは絶対に間違っている可能性があります。」それはまさに私の推論であり、元の質問からの私のジレマです。繰り返しになりますが、質問は次のとおりです。AndroidライフサイクルでExecutiveServiceをいつシャットダウンする必要がありますか?
ルーカス

2
私はAndroidの経験がありませんが、JVMを最終的に終了できるようにするには、アプリケーションがシャットダウンしたときにAndroidをシャットダウンする必要があると思います。
ジョバンニボッタ

3
そうですか。キャッシュされたスレッドプールを使用し、shutdown()それを呼び出さないことをお勧めします。これにより、不要なときにリソースを浪費しないようになります。アプリケーションがシャットダウンした場合、プール内のスレッドは最終的にガベージコレクションされます(デフォルトで60秒間アイドル状態になった後)。プールを制限したい場合、または別のスレッド寿命が必要な場合は、ThreadPoolExecutor直接作成できることに注意してください。
Giovanni Botta

13

ExecutorServiceがスレッドを再利用するという考え全体ではありませんか?では、なぜExecutorServiceをすぐに破棄するのでしょうか。

はい。ExecutorService頻繁に破棄して再作成しないでください。ExecutorService必要なときに(主に起動時に)初期化し、完了するまでアクティブのままにします。

単純にExecutorService(または必要な数に応じてカップル)を作成し、アプリケーションの実行中にタスクが発生したらタスクを渡し、アプリケーションの終了またはその他の重要な段階でそれらをシャットダウンするのは合理的な方法ではありませんか?遺言執行者?

はい。ExecutorServiceアプリケーションの終了などの重要な段階でシャットダウンするのが合理的です。

2番目の質問、Androidプラットフォームを扱う少し小さい。毎回エグゼキュータをシャットダウンするのは最善ではないと言う人がいて、Androidでプログラムしている場合、アプリケーションのさまざまなイベントを処理するときに、それらのシャットダウンをどのように処理するか(具体的には、実行するとき)を教えてください。ライフサイクル。

これExecutorServiceは、アプリケーションのさまざまなアクティビティ間で共有されていると想定します。各アクティビティは異なる時間間隔で一時停止/再開されますが、それでもExecutorServiceアプリケーションごとに1つ必要です。

ExecutorServiceアクティビティライフサイクルメソッドの状態を管理する代わりに、ExecutorService管理(作成/シャットダウン)をカスタムサービスに移動します。

ExecutorServiceサービスで作成=>onCreate()で適切にシャットダウンしますonDestroy()

シャットダウンの推奨方法ExecutorService

javaExecutorServiceを適切にシャットダウンする方法


3

システムリソースを解放し、アプリケーションを正常にシャットダウンできるようにする必要がなくなったら、ExecutorServiceをシャットダウンする必要があります。ExecutorServiceのスレッドはデーモン以外のスレッドである可能性があるため、通常のアプリケーションの終了を妨げる可能性があります。つまり、アプリケーションは、mainメソッドを完了した後も実行を続けます。

参考書

Chaper:14ページ:814


0

ExecutorServiceでshutdown()を呼び出す理由

今日、マシンで一連のタスクを開始する前に、マシンの準備ができるまで待たなければならない状況に遭遇しました。

このマシンにREST呼び出しを行います。503(サーバーが利用できません)を受信しない場合、マシンはリクエストを処理する準備ができています。したがって、最初のREST呼び出しで200(成功)が得られるまで待ちます。

これを実現するには複数の方法があります。ExecutorServiceを使用してスレッドを作成し、X秒ごとに実行するようにスケジュールしました。だから、私は条件でこのスレッドを停止する必要があります、これをチェックしてください...

final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
    Runnable task = () -> {
        try {
            int statusCode = restHelper.firstRESTCall();

            if (statusCode == 200) {
                executor.shutdown();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    };

    int retryAfter = 60;
    executor.scheduleAtFixedRate(task, 0, retryAfter, TimeUnit.SECONDS);

2番目の質問、Androidプラットフォームを扱う少し小さい。

もう少しコンテキストを提供していただければ、答えられるかもしれません。また、Android開発の私の経験から、スレッドが必要になることはめったにありません。パフォーマンスのためにスレッドを必要とするゲームまたはアプリを開発していますか?そうでない場合、Androidでは、上記で説明したシナリオのような問題に取り組む他の方法があります。コンテキストに基づいて、TimerTask、AsyncTask、またはハンドラーまたはローダーを使用できます。これは、UIThreadが長時間待機すると、何が起こるかがわかるためです:/


0

これは、ScheduledExecutorServiceなどの計画された事業にも関わらず本物です。予約された割り当ての新しいケースは実行されません。

Nの用事を実行するエージェント管理を備えた快適なアプリケーションがあることを期待する必要があります。

私はそれが楽に意味を理解していませんか?おそらく、アプリケーションにエージェント管理にさらに割り当てを送信するオプションがないようにする必要があります。その間、現在のN件の作業を完了するためにしっかりと座る必要があります。

あなたがあなたの用事が最終的に完全に肯定的である場合を除いて、あなたは与えられた休憩のためにしっかりと座って、その後単に出て、走っているひもを捨てる必要があります。

あなたの活動が干渉に反応することを意図している場合、これはうまくいきます。

もう1つの興味深い状況は、アクティビティを実行するScheduledExecutorServiceがある時点です。

アクティビティのチェーンを停止する最良の方法は、shutdown()を呼び出すことです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.