When I use CompletableFuture.allOf() to combine independent completable futures as described in the javadoc it does not reliably complete after all futures supplied to the method. E.g.:
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class CompletableFutureTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Runnable dummyTask = () -> {
try {
Thread.sleep(200);
} catch (InterruptedException ignored) {
}
};
CompletableFuture<Void> f1 = CompletableFuture.runAsync(dummyTask);
CompletableFuture<Void> f2 = CompletableFuture.runAsync(dummyTask);
CompletableFuture[] all = {f1, f2};
f1.whenComplete((aVoid, throwable) -> System.out.println("Completed f1"));
f2.whenComplete((aVoid, throwable) -> System.out.println("Completed f2"));
CompletableFuture<Void> allOf = CompletableFuture.allOf(all);
allOf.whenComplete((aVoid, throwable) -> {
System.out.println("Completed allOf");
}
);
allOf.join();
System.out.println("Joined");
}
}
Leads to the following result:
Completed f2
Joined
Completed allOf
Completed f1
I would expect the logging "Joined" and "Completed allOf" to be written after "Completed f1" and "Completed f2". To make things more confusing the order of the futures in the array seems top matter. If I changed the line
CompletableFuture[] all = {f1, f2};
to
CompletableFuture[] all = {f2, f1};
The resulting output changes to:
Completed allOf
Completed f1
Completed f2
Joined
And to make things even worse, if I run the exact same code several times, the order changes again. I could understand that the order of "f1" and "f2" change randomly, and likewise for "allOf" and "Joined". But this is really surprising.
In case it matters: This is JDK 1.8.0_91 on Windows 7.