yohhoyの日記

技術的メモをしていきたい日記

CompletableFutureのキャンセル動作

Java8で追加されたjava.util.concurrent.CompletableFutureクラスとキャンセル動作について。

  • CompletableFuture#cancelメソッドは、実行中の非同期処理に割り込み(interrupt)キャンセルしない。
  • 該当CompletableFutureが未完了の場合、CancellationException例外送出で例外完了となる。(完了済みの処理ステージには作用しない)
  • CompletableFutureに継続処理が存在する場合、キャンセル動作は後続の処理ステージ*1にのみ作用する。

メソッドチェイン形式で記述している場合、処理チェイン全体が自動的にキャンセルされる訳では無いことに注意。

// 非同期処理チェイン
CompletableFuture<V> future = CompletableFuture.
  .supplyAsync(() -> generateT())     // T generateT();
  .thenApplyAsync(t -> processT(t));  // U processT(T);
  .thenApplyAsync(u -> processU(u));  // V processU(U);
//...
future.cancel(true);

上記コードにおいて、futureは最終段thenApplyAsyncメソッドが返したCompletableFutureオブジェクトのため、cancelメソッドにより同処理ステージのみが例外完了した状態となる。このとき、未完了であってもgenerateT, processT, processUメソッドの非同期処理はそのまま継続実行され、最終的な処理結果オブジェクト(V型)は単に破棄される。

CompletableFutureには、次のポリシーを持つFutureも実装されています。

  • (FutureTaskとは異なり)このクラスは自身を完了させる計算を直接制御できないため、取消しは単に別形式の例外完了として処理されます。cancelメソッドの効果はcompleteExceptionally(new CancellationException())と同じです。isCompletedExceptionally()メソッドは、CompletableFutureが例外で完了したかどうかを判定するために使用できます。
http://docs.oracle.com/javase/jp/8/docs/api/java/util/concurrent/CompletableFuture.html

public boolean cancel(boolean mayInterruptIfRunning)

まだ完了していない場合は、このCompletableFutureをCancellationExceptionで完了します。このCancellationExceptionによってCancellationExceptionが発生するため、まだ完了していない依存するCompletableFutureも例外で完了します。

パラメータ:
mayInterruptIfRunning - 処理の制御に割込みは使用されないため、この実装ではこの値に効果はありません。

http://docs.oracle.com/javase/jp/8/docs/api/java/util/concurrent/CompletableFuture.html#cancel-boolean-

関連URL

*1:CompletableFuture クラスは CompletionStage インタフェースを実装する