I've found that CompletableFuture::join
seems uninterruptible when not completed:
// 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. I'm wondering how can I interrupt a Thread
in which I call CompletableFuture::join
.
Do not use join()
if you want to support interruption, use get()
instead. Basically they are the same except:
join()
is only defined in CompletableFuture
whereas get()
comes form interface Future
join()
wraps exceptions in CompletionException
whereas get()
wraps them in ExecutionException
get()
might be interrupted and would then throw an InterruptedException
Note that what you interrupt is the Thread
, not the Future
. For example, the following code interrupts the main thread while it is waiting on 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.
I finally give up to interrupt the Thread which blocks in waiting for CompletableFuture::join
finish.
Instead I use CompletableFuture::allof
to get a CompletableFuture
all which ends when all my joined Futures end. And then just call the get()
method of the all Future in the working thread. When get()
returns, I then collect all my results by iterating all my joined Futures and call getNow
on them. 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()
):
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());
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.