2013-04-20 9 views
45

私はこれまで数時間でかなり読んでいましたが、にshutdown()を呼び出すには何らかの理由(正当な理由)がありません。 、長年使用されていない数多くの異なるエグゼキュータサービスを提供しています。ExecutorServiceでshutdown()を呼び出す理由

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

私の質問に戻ってください。 ExecutorServiceでシャットダウンを呼び出す理由はありますか、それともいくつかのタスクをサブミットした直後ですらありますか?私は誰かがそれをやっているケースの後ろに残しておきたいと思います。それが有効であるとawaitTermination()への呼び出しの直後です。そのようにしたら、同じことをやり直すために、新しいExecutorServiceをもう一度作り直さなければなりません。 ExecutorServiceの全体のアイデアはスレッドを再利用するのではないのですか?では、なぜすぐにExecutorServiceを破壊するのですか?

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

私はExecutorServicesを使用して多くの非同期コードを書く経験豊富なコーダーからの回答を希望します。

第2の側面の質問は、少し小さくアンドロイドプラットフォームを扱います。エグゼクティブを毎回シャットダウンして、アンドロイドでプログラムするのがベストではないと言う人がいるかもしれませんが、あなたがそれらのシャットダウンをどのように扱うのかを教えてください。アプリケーションライフサイクル。

CommonsWareのコメントのため、私は投稿を中立にしました。私は本当に死に至るまで論争することに興味がなく、そこでは主導しているようだ。私は経験豊かな開発者からここに尋ねたことについて、彼らが自分の経験を共有したいと思っているかどうかを学ぶことにのみ興味があります。ありがとう。

+1

"タスクをサブミットまたは実行した直後にshutdown()呼び出しが何度も表示されることが多い" - 何度もサンプルコードが表示されるため、これは、UIThreadが長い間待機する場合に発生するためです。ハイパーリンクを使用して、あなたの主張の証拠を提供してください。個人的には、あなたが宣言している「サンプルコード」は見たことがありません。あなたが何かを誤解している可能性があります。あなたが調べている「サンプルコード」がわかっている場合にのみ、それを指摘することができます。 – CommonsWare

+2

こんにちはCommonsWare。まず第一に、私はここでは検証されていないと思うあなたの(またはそう思われる)激しいトーンを私に向かって見る。私は人を肖像画にしようとしていませんでした。あなたの見解については、私は主にThinking In Java IV版、マルチタスクの話をしていました。 Bruce Eckelの例では、その多くのインスタンスを見つけることができます。彼らはほとんどシンプルですが、ブルースが私に付けた印象は決して非常に頻繁にシャットダウンを使うことではありませんでした。いずれにせよ、あなたは私のポストの主要な部分ではなかったものに集中しました。私は本当にそれについて議論したくないので、それらの部分を削除しました。 – Lucas

+1

hay @CommonsWare in Bruce Eckel。同時実行性/実行者ページ804第4版、ExecutorがLucasとしてどのように動作するかを説明するために、シンプルなアプリケーションでタスクをサブミットまたは実行した直後に、彼は常にshutdown()メソッドを使用します。 – Error

答えて

28

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

N個のタスクを実行するエグゼキュータサービスを持つコンソールアプリケーションがあるとします。ユーザーが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は毎回呑み込まれます。これは、アプリケーション全体で再利用されるエグゼキュータ・サービスをシャットダウンする最善の方法です。

このコードは完全ではありません。タスクが最終的に終了することが確実でない限り、実行中のスレッドを破棄して、所定のタイムアウトまで待ってから終了することができます。この場合、実行中のスレッドを中断する最後の試行でタイムアウトの後にshutdownNow()を呼び出すことも意味があります(shutdownNow()は実行待ちのタスクのリストも表示します)。あなたのタスクが中断に応答するように設計されている場合、これはうまく動作します。

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

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

+0

ご迷惑をおかけしたことがありました.Giovanniさんからの返信が遅れました。ありがとうございます。はい、私は私の質問で説明しようとしたExecutorの仕組みを認識しています。シャットダウンはあなたが言ったことを行い、ガベージコレクタはデッドスレッドを収集し、事実上ExecutorServiceインスタンスを収集することができます。私の質問は具体的でした。 ExecutorService上で何かを実行/実行した直後に、常に「shutdown()」を呼び出す理由はありますか? 2番目の問題は、厳密にAndroidアーキテクチャに関連しています。前の回答が「いいえ」の場合、およびの間にシャットダウンを呼び出すタイミング。ライフサイクル。 – Lucas

+2

常にshutdown()を呼び出す理由はありません。実際には、実行者サービスを再利用できないため、絶対に間違っているかもしれません。サービスのライフサイクルの終わりに呼び出す理由は、あなたが気付いたようにスレッドが最終的にガベージコレクションされるようにするためです。そうしなければ、それらのスレッドはアイドル状態でもJVMを存続させます。 –

+0

"いつもshutdown()を呼び出す必要はありません。実際には、実行者サービスを再利用できないため、絶対に間違っているかもしれません。"それはちょうど私の推論であり、元の質問からの私のディレマです。繰り返しますが、問題は次のとおりです。AndroidライフサイクルでExecutiveServiceをいつ終了する必要がありますか? – Lucas

3

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

はい。 ExecutorServiceを頻繁に破棄して再作成しないでください。必要なときにExecutorServiceを初期化します(ほとんどの場合、起動時に起動します)。

は、それは彼らが一緒に来て、その後、アプリケーションの終了時に、またはいったんそれらにタスクをパスを実行しているアプリケーションの間に、その後、単純に(あなたが必要とするどのように多くのに応じて、または夫婦)ExecutorServiceのを作成するための合理的な方法ではありません他の重要な段階でそれらのエグゼキュータをシャットダウンする

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

2番目の側面の質問は、アンドロイドプラットフォームを少し下回っています。エグゼクティブを毎回シャットダウンして、アンドロイドでプログラムするのが最善の方法ではないと言う人がいるかもしれませんが、アプリケーションのさまざまなイベントを処理するときに、シャットダウンをどのように処理するか(具体的には、実行するとき)ライフサイクル。

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

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

ExecutorServiceをシャットダウンするonDestroy()

推奨の方法でそれを適切にサービス=>onCreate()ExecutorServiceを作成し、シャットダウン:シャットダウンを呼び出すための

How to properly shutdown java ExecutorService

0

理由()ExecutorServiceの

今日私は私が待つ必要がある状況に遭遇しましたそのマシン上で一連のタスクを開始する前に、マシンは準備完了です。

このマシンにREST呼び出しを行います.503(サーバー使用不可)が表示されない場合、マシンは自分の要求を処理する準備ができています。だから、最初のREST呼び出しで200(成功)になるまで待つ。

これを達成する方法は複数ありますが、ExecutorServiceを使用してスレッドを作成し、X秒ごとに実行するようにスケジュールしました。だから、私はAndroidプラットフォームと少し小さい取引、...

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); 

第二側の質問を、条件にこのスレッドを停止し、これをチェックアウトする必要があります。

多分もっと文脈を提供すれば答えられるかもしれません! また、Android開発の経験から、スレッドはほとんど必要ありません。パフォーマンスのためにスレッドを必要とするゲームやアプリを開発していますか?そうでない場合は、Androidで上記のシナリオのような問題に取り組む他の方法があります。代わりに、コンテキストに基づいてTimerTask、AsyncTaskまたはHandlersまたはLoaderを使用できます。/

関連する問題