I seem to fail miserably at an apparently simple example with CompletableFuture
.
I have a CompletableFuture
that is blocked in a different thread, something like:
Supplier<CompletableFuture<String>> one = () -> CompletableFuture.supplyAsync(() -> {
System.out.println("started cf");
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(3));
System.out.println("done cf");
return "";
});
ExecutorService service = Executors.newSingleThreadExecutor();
service.submit(() -> {
try {
future = one.get();
future.get();
} catch (Exception e) {
System.out.println("caught");
future.completeExceptionally(e);
}
});
I want to be able to cancel
it, and then join
to wait until it is completed in a thread that is different then the one above, so something like this:
static CompletableFuture<String> future;
public static void main(String[] args) {
Supplier<CompletableFuture<String>> one = () -> CompletableFuture.supplyAsync(() -> {
System.out.println("started cf");
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(3));
System.out.println("done cf");
return "";
});
ExecutorService service = Executors.newSingleThreadExecutor();
service.submit(() -> {
try {
future = one.get();
future.get();
} catch (Exception e) {
System.out.println("caught");
future.completeExceptionally(e);
}
});
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
future.cancel(true);
System.out.println("before join");
String s = future.join();
System.out.println("s value : " + s);
System.out.println("done");
}
To my surprise, this one String s = future.join();
blocks and I don't understand why.
More surprising, if I change my code to (instead of String s = future.join();
):
String s = null;
try {
s = future.join();
} catch(Exception e) {
System.out.println("here : " + e.getClass());
}
this one does not block. Can someone please shed some light here?
With or without the try/catch
around future.join()
this blocks for me in the same way, whereby I define "blocking" here as: I put your code into a file, run it from the command line and the process does not finish.
The reason is that Executors.newSingleThreadExecutor()
works with a non-daemon thread, meaning the pool's thread keeps on running even when the main()
method returns (you should see your "done" output). Consequently the program's process does not finish.
You may either
service.shutdown()
or some of its variants before future.join()
ornewSingleThreadExecutor(ThreadFactory)
where the thread factory provides a daemon thread (.setDaemon(true)
)