tl; dr; Future.cancel(false)まだ開始されていないタスクの開始を回避する場合にのみ役立ちます。
並行性とキャンセルに関して理解すべき2つの重要なことがあります。
1つ目は、Javaではキャンセルは純粋に協調的であるということです。Javaは、ブロッキングメソッドにInterruptedExcetionsをスローさせ、スレッドにフラグを設定することにより、キャンセル要求を通知します。タスクの実装は、キャンセル要求に気づき、それ自体をキャンセルする責任があります。Brian Goetzは、彼の投稿「InterruptedExceptionの処理」で中断について説明しています。すべてのタスク実装が中断を正しく処理するわけではありません。
次に指摘するのは、Futureオブジェクトは、将来実行されるタスクの結果のプレースホルダーであるということです。実行中のスレッドがたくさんない場合は、タスクがすぐに実行を開始する可能性がありますが、すべてのスレッドがすでに使用されており、タスクが待機する必要がある可能性もあります。Futureオブジェクトへの参照があるからといって、対応するタスクが実際に実行を開始したことを意味するわけではありません。それは予約のようなものです。
Futureオブジェクトがありますが、タスクは次のいずれかの状態になっている可能性があります。
- 待っている。たとえば、プロセッサ時間を待機している他のタスクのキューにある可能性があります。
- ランニング。
- 完了しました。
タスクが最初の状態「待機中」の場合、両方ともFuture.cancel(true)将来Future.cancel(false)がキャンセル済みとしてマークされます。タスクは実行するタスクのキューに残りますが、エグゼキュータがタスクに到達すると、キャンセルされたフラグに気づき、それをスキップします。
タスクが両方よりも「完了」の3番目の状態にあり、 falseFuture.cancel(true)をFuture.cancel(false)返し、何もしない場合。それらはすでに完了しており、元に戻す方法がないため、これは理にかなっています。
mayInterruptIfRunningフラグは、タスクが2番目の状態「実行中」の場合にのみ重要です。
タスクが実行中でmayInterruptIfRunningfalseの場合、エグゼキュータは何もせず、タスクの完了を許可します。
タスクが実行中であり、mayInterruptIfRunningtrueの場合、エグゼキュータはタスクを中断します。ただし、協調キャンセルについて少し覚えておいてください。中断が機能するためには、キャンセルを処理するためにタスクを実装する必要があります。
概要:
Future.cancel(true)次の場合に適切です。
- Futureは、中断を処理するために実装されたことが知られている長期実行タスクを表します。
Future.cancel(false)正しいでしょう:
- タスクの実装は、中断された処理を処理できません。
- タスクの実装がキャンセルをサポートしているかどうかは不明です。
- すでに開始されているタスクが完了するのを待つことができます。