【问题标题】:How to interrupt CompletableFuture::join?如何中断 CompletableFuture::join?
【发布时间】:2023-03-28 03:01:01
【问题描述】:

我发现CompletableFuture::join 在未完成时似乎不间断

// CompletableFuture::join implementation from JDK 8 sources
public T join() { 
    Object r;
    return reportJoin((r = result) == null ? waitingGet(false) : r);
}

在上述实现中,waitingGet(false) 将忽略工作中的Thread 的中断标志并继续等待。我想知道如何打断我调用CompletableFuture::joinThread

【问题讨论】:

  • 我想知道这是不是你要找的东西:stackoverflow.com/questions/43389894/…
  • @Eugene 谢谢你的链接。我知道CompletableFuture::cancel 不会中断线程。我想要做的是中断在CompletableFuture::join 操作中阻塞的线程。也许我应该更清楚地描述我的问题。

标签: java multithreading java-8 interrupt completable-future


【解决方案1】:

如果要支持中断,请不要使用join(),而是使用get()。基本上它们是相同的,除了:

  • join() 仅在 CompletableFuture 中定义,而 get() 来自接口 Future
  • join() 将异常包装在 CompletionException 中,而 get() 将它们包装在 ExecutionException
  • get() 可能会被打断,然后会抛出 InterruptedException

请注意,您中断的是Thread,而不是Future。例如,以下代码在主线程等待myFuture.get() 时中断它:

CompletableFuture<Void> myFuture = new CompletableFuture<>();
Thread mainThread = Thread.currentThread();
CompletableFuture.runAsync(() -> {
    try {
        Thread.sleep(1000);
        System.out.println("Interrupting…");
        mainThread.interrupt();
        Thread.sleep(1000);
        System.out.println("Completing");
        myFuture.complete(null);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
});
try {
    myFuture.get();
    System.out.println("Get succeeded");
} catch (Exception e) {
    System.out.println("Get failed");
    e.printStackTrace();
}

输出:

Interrupting…
Get failed
java.lang.InterruptedException
    at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:347)
    at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
    at CompletableFutureInteruption.main(CompletableFutureInteruption.java:37)
    …

如果将get()替换为join(),则中断确实不起作用。

【讨论】:

  • 感谢您指出join()get() 之间的区别。
  • 方法join() 是在CompletableFuture 中定义的,而不是CompletionStage(第一个要点)。尽管考虑到CompletionStagetoCompletableFuture() 方法,接口和实现看起来紧密耦合。
  • 谢谢@Slaw,我现在修好了
【解决方案2】:

我终于放弃中断等待CompletableFuture::join完成的线程。

相反,我使用CompletableFuture::allof 获得CompletableFuture all,当我加入的所有 Futures 结束时结束。然后在工作线程中调用 all Future 的get() 方法。当get() 返回时,我通过迭代所有加入的 Future 来收集我的所有结果,并在它们上调用getNow。这样的过程是可中断的。

【讨论】:

  • 看起来这是an XY problem然后...
  • @DidierL 是的,我只是想要一种可中断的方式来“加入”所有期货并获得结果。我应该澄清一下。
  • 我看不出allOf() 和中断在这里实际上是如何相互关联的。 allOf() 可以在没有中断的情况下解决问题,或者您需要中断但您正在处理 allOf() 调用的结果并不重要。
  • 与中断相关的是get()。你说的对。实际上我有一堆期货,想加入他们并得到结果。所以我提到allOf()结合get()
  • 那么你是怎么打断的呢?请举例?
【解决方案3】:

我清楚地知道你到底不是实际上在寻找可中断,但作为一种解决方法可以被异常打断如下(虽然是join()):

private static void testCompleteExceptionally() {
    String name = "Hearen";
    CompletableFuture<String> completableFuture
            = CompletableFuture.supplyAsync(() -> {
        delay(500L);
        if (name == null) {
            throw new RuntimeException("Computation error!");
        }
        return "Hello, " + name;
    });

    if (name != null) {
        completableFuture.completeExceptionally(new RuntimeException("Calculation failed!"));
    }
    out.println(completableFuture.handle((s, t) ->  s != null ? s : "Hello, Stranger!" + t.toString()).join());
}

【讨论】:

    猜你喜欢
    • 2019-02-21
    • 2018-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-16
    相关资源
    最近更新 更多