There are 2 ways to to force a CompletableFuture to timeout after a given amount of time:
I would expect them to behave the same. However, when applied to CompletableFuture.allOf(CompletableFuture<?>... cfs), these 2 ways of providing a timeout behave quite differently !
Basically, it seems that get() does what I would expect (it blocks the current thread until all futures have completed), whereas orTimeout() seems to behave very strangely (it unblocks the current thread as soon as it can after the first future has completed).
Here's some code to demo the behavior I am observing:
import org.junit.Test;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeoutException;
import static java.util.concurrent.TimeUnit.MILLISECONDS;
public class AllOfWithTimeoutTest {
public static final int TIMEOUT_IN_MILLIS = 100;
@Test
public void allOfOrTimeout1() throws InterruptedException, ExecutionException, TimeoutException {
getAllOfFuture().get(TIMEOUT_IN_MILLIS, MILLISECONDS);
}
@Test
public void allOfOrTimeout2() throws ExecutionException, InterruptedException {
getAllOfFuture().orTimeout(TIMEOUT_IN_MILLIS, MILLISECONDS);
}
private CompletableFuture<Void> getAllOfFuture() {
return CompletableFuture.allOf(
CompletableFuture.runAsync(() -> sleep(1)),
CompletableFuture.runAsync(() -> sleep(2)),
CompletableFuture.runAsync(() -> sleep(3)),
CompletableFuture.runAsync(() -> sleep(4)),
CompletableFuture.runAsync(() -> sleep(5)),
CompletableFuture.runAsync(() -> sleep(6)),
CompletableFuture.runAsync(() -> sleep(7)),
CompletableFuture.runAsync(() -> sleep(8))
);
}
public static void sleep(int millis) {
try {
Thread.sleep(millis);
System.out.format("Had a nap for %s milliseconds.\r\n", millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
};
}
The printout of allOfOrTimeout1() is what I would expect:
Had a nap for 1 milliseconds.
Had a nap for 2 milliseconds.
Had a nap for 3 milliseconds.
Had a nap for 4 milliseconds.
Had a nap for 5 milliseconds.
Had a nap for 6 milliseconds.
Had a nap for 7 milliseconds.
Had a nap for 8 milliseconds.
The printout of allOfOrTimeout2() is NOT what I would expect, and varies slightly at every execution. It typically prints out between the first 2 and 5 lines, but never 8. Here's a version where it printed out only 2 lines:
Had a nap for 1 milliseconds.
Had a nap for 2 milliseconds.
Also, if I run the whole test in IntelliJ, I get some extra lines at the end:
Had a nap for 1 milliseconds.
Had a nap for 2 milliseconds.
Had a nap for 3 milliseconds.
Had a nap for 4 milliseconds.
Had a nap for 5 milliseconds.
Had a nap for 6 milliseconds.
Had a nap for 7 milliseconds.
Had a nap for 8 milliseconds.
Had a nap for 1 milliseconds.
Had a nap for 2 milliseconds.
Had a nap for 3 milliseconds.
Had a nap for 4 milliseconds.
Process finished with exit code 0
Had a nap for
My questions are:
- Is this the expected behavior for
orTimeout()? - If not, why is it doing this ?