設計上、割り込みによる実行の制御は行われないことは承知しています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();
}
これは、実行中のタスクが割り込みを正しく処理するように設定されていることを前提としています。