Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 913
phil Avatar asked May 28 '17 19:05

phil


People also ask

How do I interrupt CompletableFuture?

As such, there's nothing you can do through CompletableFuture to interrupt any thread that may be running some task that will complete it. You'll have to write your own logic which tracks any Thread instances which acquire a reference to the CompletableFuture with the intention to complete it.

Is join on CompletableFuture blocking?

The answer is that join() may block the thread, but if this happens inside a worker thread of a Fork/Join pool, this situation will be detected and a new compensation thread will be started, to ensure the configured target parallelism.

What is join in CompletableFuture?

The CompletableFuture. join() method is similar to the get method, but it throws an unchecked exception in case the Future does not complete normally. This makes it possible to use it as a method reference in the Stream. map() method.

Does join throw interrupted exception?

join(): It will put the current thread on wait until the thread on which it is called is dead. If thread is interrupted then it will throw InterruptedException.


1 Answers

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.

like image 158
Didier L Avatar answered Nov 09 '22 23:11

Didier L