Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

is it safe/good practice to "reuse" CompletableFuture

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?

like image 216
user140547 Avatar asked Aug 16 '16 13:08

user140547


People also ask

Can CompletableFuture be reused?

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.

When should I use CompletableFuture?

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.

What is Completable future How does it compare to future?

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.

Is CompletableFuture blocked?

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.


1 Answers

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”.

like image 152
Holger Avatar answered Sep 30 '22 01:09

Holger