When experimenting with CompletableFuture
, I was wondering if the given code is safe.
CompletableFuture<Integer> foo = CompletableFuture.supplyAsync(() -> 42);
foo.thenApply((bar) -> {
System.out.println("bar " + bar);
return bar;
})
.acceptEither(foo.thenApply((baz) -> {
System.out.println("baz " + baz);
return baz;
}),
(z) -> System.out.println("finished processing of " + z));
It works, printing
bar 42
baz 42
finished processing of 42
Is it safe/a good idea to call thenApply
or other methods more than once on a given instance of CompletableFuture
?
What you describe is not a “reuse” of a CompleteableFuture , as it still performs only one action and completes at most once. A stage of a possibly asynchronous computation, that performs an action or computes a value when another CompletionStage completes.
CompletableFuture is used for asynchronous programming in Java. Asynchronous programming is a means of writing non-blocking code by running a task on a separate thread than the main application thread and notifying the main thread about its progress, completion or failure.
A CompletableFuture is an extension to Java's Future API which was introduced in Java 8. A Future is used for asynchronous Programming. It provides two methods, isDone() and get(). The methods retrieve the result of the computation when it completes.
CompletableFuture allows us to write non-blocking code by running a task on a separate thread than the main application thread and notifying the main thread about its Progress, Completion or Failure. CompletableFuture is inspired from ListenableFuture in Guava and Are similar to Promise in java scripts.
What you describe is not a “reuse” of a CompleteableFuture
, as it still performs only one action and completes at most once.
You are just registering multiple dependent stages, which is completely within the foreseen usage. At no point, the documentation suggested that dependent stages had to form a single linear chain. The use case is already described by the interface CompletionStage<T>
:
A stage of a possibly asynchronous computation, that performs an action or computes a value when another CompletionStage completes. A stage completes upon termination of its computation, but this may in turn trigger other dependent stages.
Note the use of “other dependent stages” rather then “another dependent stage”. The entire documentation consistently uses plural when it comes to dependent stages. This also applies to the documentation of the CompletableFuture<T>
implementation class.
After all, when you have two actions a and b which have no dependency to each other but a dependency to c, the only thing that makes sense, is to chain both to c rather than create a chain like c → a → b or c → b → a as the latter would inhibit the concurrent execution of the independent actions a and b, which is the entire point of the concurrency API.
Note that when modelling the dependency this way, there is no guaranty of the outcome you have shown. The two printing actions “bar” and “baz” have no dependency on each other, but only on the supplier of the 42
value, and the action which prints “finished processing” is scheduled for the completion of either of them, not both. So besides the indeterminate order of the “bar” and “baz” output, you could also see a log like “bar, finished processing, baz” or “baz, finished processing, bar”.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With