I'm studying CompletableFuture
in Java 1.8 and having trouble trying to understand allOf
. It seems the main thread doesn't wait for any CompletableFuture
to complete.
See https://github.com/nurkiewicz/reactive/blob/master/src/test/java/be/more/reactive/S03_AllOf.java for the example I'm testing.
The test job finishes before any result is printed.
There are two (ugly?) ways to circumvent this: 1) set a timeout on the main thread and wait for both to finish. 2) set a .get()
at the end and it will become a blocking task.
Why is this?
Code fragment:
package be.more.reactive;
import be.more.reactive.util.BaseTest;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.CompletableFuture;
public class S03_AllOf extends BaseTest {
private static final Logger log = LoggerFactory.getLogger(S03_AllOf.class);
private final CompletableFuture<String> futureResult1 = getFutureQueryResult("1"); //.exceptionally() ??
private final CompletableFuture<String> futureResult2 = getFutureQueryResult("2");
private final CompletableFuture<String> futureResult3 = getFutureQueryResult("3");
private final CompletableFuture<String> futureResult4 = getFutureQueryResult("4");
@Test
public void allOf() throws Exception {
final CompletableFuture<Void> futureResult = CompletableFuture.allOf( //Void ?? I want List<String>
futureResult1, futureResult2, futureResult3, futureResult4
);
// futureResult.thenAccept((Void vd) -> vd.??) //no, it won't work
futureResult.thenRun(() -> {
try {
log.debug("Query result 1: '{}'", futureResult1.get());
log.debug("Query result 2: '{}'", futureResult2.get());
log.debug("Query result 3: '{}'", futureResult3.get());
log.debug("Query result 4: '{}'", futureResult4.get()); //a lot of manual work
log.debug("Now do on complete"); //handling onComplete
} catch (Exception e) {
log.error("", e);
}
});
}
}
And in BaseTest:
protected CompletableFuture<String> getFutureQueryResult(final String queryId) {
return CompletableFuture.supplyAsync(
() -> db.apply(new Query(queryId))
);
}
And in DB.java
package be.more.reactive.db;
import java.util.concurrent.TimeUnit;
import static org.apache.commons.lang3.RandomStringUtils.randomAlphabetic;
import static org.apache.commons.lang3.RandomUtils.nextInt;
import static org.apache.commons.lang3.RandomUtils.nextLong;
public class DB {
public String apply(Query query) {
try {
TimeUnit.SECONDS.sleep(nextLong(2, 4));
} catch (InterruptedException e) {
e.printStackTrace();
}
return String.format("%s_%s", randomAlphabetic(nextInt(4, 12)), query.getId());
}
}