简体   繁体   中英

How to interrupt CompletableFuture::join?

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.

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