web-dev-qa-db-ja.com

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

私は過去数時間でそれについてかなり読んでいましたが、ExecutorServiceshutdown()を呼び出す理由(有効理由)がまったくわかりません。長い間使用されていないさまざまなエグゼキューターサービスを格納、数十、数十とする巨大なアプリケーションがあります。

(私が収集したものから)シャットダウンが行う唯一のことは、いったん終了すると通常のスレッドが行うことです。通常のスレッドがRunnable(またはCallable)のrunメソッドを終了すると、収集されるガベージコレクションに渡されます。 Executor Serviceを使用すると、スレッドは単に保留状態になり、ガベージコレクションの対象になりません。そのためにはシャットダウンが必要です。

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

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

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

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

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

69
Lucas

shutdown()メソッドは、クライアントがexecutorサービスにさらに多くの作業を送信することを防ぎます。つまり、他のアクションが実行されない限り、既存のタスクはすべて完了まで実行されます。これは、ScheduledExecutorServiceなど、スケジュールされたタスクにも当てはまります。スケジュールされたタスクの新しいインスタンスは実行されません。これはさまざまなシナリオで役立ちます。

N個のタスクを実行するexecutorサービスを備えたコンソールアプリケーションがあるとします。ユーザーがCTRL-Cを押すと、おそらく正常にアプリケーションが終了するはずです。優雅にどういう意味ですか?アプリケーションでexecutorサービスにこれ以上のタスクを送信できないようにすると同時に、既存の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は毎回飲み込まれます。これは、アプリケーション全体で再利用されるexecutorサービスをシャットダウンする最良の方法です。

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

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

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

44
Giovanni Botta

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

はい。 ExecutorServiceを頻繁に破棄および再作成しないでください。必要に応じて(主に起動時に)ExecutorServiceを初期化し、完了するまでアクティブに保ちます。

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

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

2番目の質問は、少し小さいAndroidプラットフォームです。毎回executorをシャットダウンするのがベストとは言えないという意見があり、Androidでプログラムする場合は、アプリケーションのライフサイクルのさまざまなイベントを処理するときに、これらのシャットダウンを処理します(具体的には、実行時に)。

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

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

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

ExecutorServiceをシャットダウンする推奨方法:

適切にシャットダウンする方法Java ExecutorService

7
Ravindra babu

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

参考書

Chaper:14ページ:814

3
emon

これは、ScheduledExecutorServiceのように、計画された事業に関係なく、本物です:予約された割り当ての新しいケースは実行されません。

N管理を実行するエージェント管理機能を備えたコンフォートアプリケーションが必要です。

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

最後にあなたの使いが完全に肯定的である場合を除いて、あなたは与えられた休憩のためにきつく座って、それから単に出て、走っている弦を捨てる必要があります。

アクティビティが干渉に反応することを意図している場合、これはうまく機能します。

もう1つの興味深い状況は、アクティビティを再生するScheduledExecutorServiceがあるポイントです。

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

0
Devlax

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

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

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

それを実現する方法は複数あります。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またはHandlersまたはLoadersを使用することもできます。