如何打断CompletableFuture::join?
How to interrupt CompletableFuture::join?
我发现 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::join
.
的 Thread
如果要支持中断,请不要使用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()
,中断确实不行
我终于放弃中断阻塞等待CompletableFuture::join
完成的Thread。
相反,我使用 CompletableFuture::allof
来获得 CompletableFuture
all,当我加入的所有 Futures 结束时结束。然后在工作线程中调用 all Future 的 get()
方法。当 get()
returns 时,我会通过迭代所有加入的 Futures 并在它们上调用 getNow
来收集所有结果。这样的过程是可中断的。
我清楚地知道你最终不是实际上在寻找可中断,但作为一种绕过它的方法可以被中断异常如下(虽然是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());
}
我发现 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::join
.
Thread
如果要支持中断,请不要使用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()
,中断确实不行
我终于放弃中断阻塞等待CompletableFuture::join
完成的Thread。
相反,我使用 CompletableFuture::allof
来获得 CompletableFuture
all,当我加入的所有 Futures 结束时结束。然后在工作线程中调用 all Future 的 get()
方法。当 get()
returns 时,我会通过迭代所有加入的 Futures 并在它们上调用 getNow
来收集所有结果。这样的过程是可中断的。
我清楚地知道你最终不是实际上在寻找可中断,但作为一种绕过它的方法可以被中断异常如下(虽然是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());
}