简体   繁体   English

如何中断CompletableFuture :: join?

[英]How to interrupt CompletableFuture::join?

I've found that CompletableFuture::join seems uninterruptible when not completed: 我发现CompletableFuture::join在未完成时似乎是不可中断的

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

In above implementation, waitingGet(false) will ignore the interrupt flag of the working Thread and continue waiting. 在上面的实现中, waitingGet(false)将忽略工作Thread的中断标志并继续等待。 I'm wondering how can I interrupt a Thread in which I call CompletableFuture::join . 我想知道如何中断我称之为CompletableFuture::joinThread

Do not use join() if you want to support interruption, use get() instead. 如果要支持中断,请不要使用join() ,而是使用get() Basically they are the same except: 基本上它们是相同的,除了:

  • join() is only defined in CompletableFuture whereas get() comes form interface Future join()仅在CompletableFuture定义,而get()来自表单接口Future
  • join() wraps exceptions in CompletionException whereas get() wraps them in ExecutionException join()CompletionException包装异常,而get()ExecutionException包装它们
  • get() might be interrupted and would then throw an InterruptedException get()可能会被中断,然后会抛出InterruptedException

Note that what you interrupt is the Thread , not the Future . 请注意,您打断的是Thread ,而不是Future For example, the following code interrupts the main thread while it is waiting on myFuture.get() : 例如,以下代码在等待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();
}

Output: 输出:

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)
    …

If you replace get() by join() , the interrupt will indeed not work. 如果用join()替换get() ,则中断确实不起作用。

I finally give up to interrupt the Thread which blocks in waiting for CompletableFuture::join finish. 我终于放弃了在等待CompletableFuture::join完成时阻塞的Thread。

Instead I use CompletableFuture::allof to get a CompletableFuture all which ends when all my joined Futures end. 相反,我使用CompletableFuture::allof来获得CompletableFuture 所有这些都在我所有加入的期货结束时结束。 And then just call the get() method of the all Future in the working thread. 然后在工作线程中调用所有 Future的get()方法。 When get() returns, I then collect all my results by iterating all my joined Futures and call getNow on them. get()返回时,我会通过迭代所有已加入的Futures并在其上调用getNow来收集我的所有结果。 Such a procedure is interruptible. 这样的程序是可以中断的。

I clearly known in the end you are not actually looking for the interruptible , but as a way around it can be interrupted by exceptions as follows (though it's join() ): 我最后清楚地知道你实际上并不是在寻找可中断的 ,但是作为一种解决方法可能会被例外中断,如下所示(尽管它是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());
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM