16

falseどのような状況でmayInterruptIfRunningパラメータをに渡したいFuture.cancel()ですか?

私が正しく理解していれば、合格falseしてタスクがキャンセルされたがスレッドが中断されていないExecutionException場合、タスクはまだキャンセル済みとしてマークされているため、結果(または)にアクセスすることはできません(つまり、isCancelled()戻りtrueget()スローしCancellationExceptionます)。

その他の考えられる状況は次のとおりです。

  • Runnableまたは実装は割り込みをチェックせず、Callable割り込みを行っても完了まで実行されます(ここでは割り込みは違いがありません)
  • 電話をかける前にすでに完了したタスクcancel()(ここでも割り込みは違いはありません)
  • タスクは、終了する前にクリーンアップを実行する必要があります(適切に記述された実装がtry ... finallyこれに使用されます)。
  • タスクはすぐに終了することはできず、I / Oのブロックなど、割り込みの影響を受ける操作を実行し続ける必要があります(この場合、おそらくまったく呼び出さないcancelでください) 。

では、いつ/なぜタスクを中断せずにキャンセルするのでしょうか。

4

3 に答える 3

20

tl; dr; Future.cancel(false)まだ開始されていないタスクの開始を回避する場合にのみ役立ちます。

並行性とキャンセルに関して理解すべき2つの重要なことがあります。

1つ目は、Javaではキャンセルは純粋に協調的であるということです。Javaは、ブロッキングメソッドにInterruptedExcetionsをスローさせ、スレッドにフラグを設定することにより、キャンセル要求を通知します。タスクの実装は、キャンセル要求に気づき、それ自体をキャンセルする責任があります。Brian Goetzは、彼の投稿「InterruptedExceptionの処理」で中断について説明しています。すべてのタスク実装が中断を正しく処理するわけではありません。

次に指摘するのは、Futureオブジェクトは、将来実行されるタスクの結果のプレースホルダーであるということです。実行中のスレッドがたくさんない場合は、タスクがすぐに実行を開始する可能性がありますが、すべてのスレッドがすでに使用されており、タスクが待機する必要がある可能性もあります。Futureオブジェクトへの参照があるからといって、対応するタスクが実際に実行を開始したことを意味するわけではありません。それは予約のようなものです。

Futureオブジェクトがありますが、タスクは次のいずれかの状態になっている可能性があります。

  1. 待っている。たとえば、プロセッサ時間を待機している他のタスクのキューにある可能性があります。
  2. ランニング。
  3. 完了しました。

タスクが最初の状態「待機中」の場合、両方ともFuture.cancel(true)将来Future.cancel(false)がキャンセル済みとしてマークされます。タスクは実行するタスクのキューに残りますが、エグゼキュータがタスクに到達すると、キャンセルされたフラグに気づき、それをスキップします。

タスクが両方よりも「完了」の3番目の状態にあり、 falseFuture.cancel(true)Future.cancel(false)返し、何もしない場合。それらはすでに完了しており、元に戻す方法がないため、これは理にかなっています。

mayInterruptIfRunningフラグは、タスクが2番目の状態「実行中」の場合にのみ重要です。

タスクが実行中でmayInterruptIfRunningfalseの場合、エグゼキュータは何もせず、タスクの完了を許可します。

タスクが実行中であり、mayInterruptIfRunningtrueの場合、エグゼキュータはタスクを中断します。ただし、協調キャンセルについて少し覚えておいてください。中断が機能するためには、キャンセルを処理するためにタスクを実装する必要があります。

概要:

Future.cancel(true)次の場合に適切です。

  1. Futureは、中断を処理するために実装されたことが知られている長期実行タスクを表します。

Future.cancel(false)正しいでしょう:

  1. タスクの実装は、中断された処理を処理できません。
  2. タスクの実装がキャンセルをサポートしているかどうかは不明です。
  3. すでに開始されているタスクが完了するのを待つことができます。
于 2011-08-04T17:59:30.863 に答える
9

タスクの実行を中断すると、状態が悪くなる可能性があり、ユーザーがタスクをFuture認識できるように、タスクをキャンセル済みとしてマークするだけです(たとえば、要求された統計が時間どおりに実行されなかったことを知っておく必要があります)。 )。

割り込みを正しく処理するスレッドコードを書くことは決して簡単ではないので、単にそれを避けたいと思うかもしれません。

いくつかの情報は、ここここ、そしてもちろん、Javaでの並行プログラミング(最初に書いた人によるjava.util.concurrent)の素晴らしい本で見つけることができます。

于 2010-07-17T13:35:57.030 に答える
1

興味深いユースケースがあります。スケジュールされたタスクのセットを実行している単一のスレッドがあります。タスクの1つは、それ自体または別のタスクによって再スケジュールされる場合があります。

これを行うFuture.cancel(false)には、キュー内の既存のコピーを使用してから、新しい時間にタスクをスケジュールします。

このコードがスケジュールされたタスク自体から呼び出された場合、キャンセル操作はノーオペレーションになり、タスクは将来再び実行されるようにスケジュールされます。コードが別のコンテキストから呼び出された場合、次のタスクはまだ実行を開始していないため、キャンセルされ、新しい時間にスケジュールされたタスクに置き換えられます。

于 2015-12-08T23:27:30.247 に答える