Pissed cause your hustles ain't worth a shit
— Obie Trice, Cry Now (Shady Remix)
Chained CompletableFutures - Java 8
Berlin, Germany - Wednesday, Jun 22 2016
Extract from the dumb question I asked on StackOverflow:
So I have a method that returns a CompletableFuture. Before returning, this method adds a block with thenAccept which is executed after the CompletableFuture completes.
The caller of this method also adds another block with thenAccept. Obviously this can go on with multiple
In what order are the CompletionStage returned by the thenAccept invocations executed? Is it guaranteed to be
the order in which they are added? If not, how can one guarantee that they are executed in the order in which they are added?
I was dumb enough to believe that blocks are executed in order. Might be I am not too dumb, I was obviously not well
convinced and that led me to asking on StackOverflow
The only answer to the question suggested to use CompletableFuture#thenAcceptBoth which takes a CompletionStage and
a BiConsumer as arguments. This is assuming that I need a result from the CompletionStages returned from the
chained thenAccept because the BiConsumer consumes the result of the CompletableFuture and the CompletionStage.
My use case doesn’t need the CompletionStages. Different components of the system need a Future.
Here is what I was doing before asking the question looks like
The thenAccept methods from the two components are not guaranteed to be executed in the desired order. What then do I
do if I want to guarantee the order of execution? Thanks to Achim who suggested this to me because I was too lazy to
read the documentation, I ended up using thenApply
What is the difference between the two? The first approach consumes the value from the Future on the same thread of
the caller and not that of the Future and thus we can’t guarantee order of execution. When the Future
completes the consumers are triggered and invoked by their own thread.
The second approach on the other hand ties the consumption to the Future returned to the caller which enforces the
consumption before the Future returned to the caller terminates and invokes the next consumer. In fact, the
Future returned to the second component involves the consumption from the first component.
The added bonus of the second approach is that we can return something else from the first (or second) component and
not necessarily the template type of the Future returned from the base component. Something like this