CompletableFuture の基盤となる実行を中断する方法 質問する

CompletableFuture の基盤となる実行を中断する方法 質問する

設計上、割り込みによる実行の制御は行われないことは承知していますCompletableFutureが、この問題を抱えている方もいらっしゃると思います。CompletableFutureは非同期実行を構成するための非常に優れた方法ですが、future がキャンセルされたときに基礎となる実行を中断または停止したい場合、どうすればよいでしょうか。それとも、キャンセルまたは手動で完了しても、CompletableFutureそれを完了するためにそこで動作しているスレッドには影響がないと受け入れるしかないのでしょうか。

それは、私の意見では、実行者の時間を奪う、明らかに無駄な作業です。この場合、どのようなアプローチや設計が役立つのでしょうか?

アップデート

これについての簡単なテストがあります

public class SimpleTest {

  @Test
  public void testCompletableFuture() throws Exception {
    CompletableFuture<Void> cf = CompletableFuture.runAsync(()->longOperation());

    bearSleep(1);

    //cf.cancel(true);
    cf.complete(null);

    System.out.println("it should die now already");
    bearSleep(7);
  }

  public static void longOperation(){
    System.out.println("started");
    bearSleep(5);
    System.out.println("completed");
  }

  private static void bearSleep(long seconds){
    try {
      TimeUnit.SECONDS.sleep(seconds);
    } catch (InterruptedException e) {
      System.out.println("OMG!!! Interrupt!!!");
    }
  }
}

ベストアンサー1

CompletableFuture最終的に完了する可能性のある非同期アクションとは関係ありません。

このクラスは( とは異なりFutureTask) 完了の原因となる計算を直接制御しないため、キャンセルは例外的な完了の別の形式として扱われます。 メソッドはcancelと同じ効果を持ちますcompleteExceptionally(new CancellationException())

ないかもしれないなれそれを完成させるための別のスレッド(多くのたとえあったとしても、CompletableFutureそれを参照しているスレッドへのリンクはありません。

そのため、CompletableFutureそれを完了するタスクを実行している可能性のあるスレッドを中断する方法はありません。それを完了する目的Threadで参照を取得するインスタンスを追跡する独自のロジックを作成する必要があります。CompletableFuture


ここに、あなたが逃げおおせる可能性があると思われる処刑方法の例を示します。

public static void main(String[] args) throws Exception {
    ExecutorService service = Executors.newFixedThreadPool(1);
    CompletableFuture<String> completable = new CompletableFuture<>();
    Future<?> future = service.submit(new Runnable() {
        @Override
        public void run() {
            for (int i = 0; i < 10; i++) {
                if (Thread.interrupted()) {
                    return; // remains uncompleted
                }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    return; // remains uncompleted
                }
            }
            completable.complete("done");
        }
    });

    Thread.sleep(2000);

    // not atomic across the two
    boolean cancelled = future.cancel(true);
    if (cancelled)
        completable.cancel(true); // may not have been cancelled if execution has already completed
    if (completable.isCancelled()) {
        System.out.println("cancelled");
    } else if (completable.isCompletedExceptionally()) {
        System.out.println("exception");
    } else {
        System.out.println("success");
    }
    service.shutdown();
}

これは、実行中のタスクが割り込みを正しく処理するように設定されていることを前提としています。

おすすめ記事