Asynchronous API with CompletableFuture: Performance Tips and Tricks

Java · 27K views · 2017 · 44:35

Open on YouTube

Software performance & optimizationC, C++, Rust, Go & systems languagesSoftware architecture & designtalk

Why Stack Overflow recommends it

Stack Overflow users link it when answering questions about which thread runs CompletableFuture stages and whether callbacks beat blocking Futures, since the speaker built the API and explains its internals.

Recommended by 1 people across 1 different months, 2019 to 2023.

What it is

A conference talk by Oracle engineer Sergey Kuksenko on building asynchronous APIs with Java's CompletableFuture. It goes past the public API to cover internal implementation details and the performance consequences of how stages are chained and executed.

What people said

Recommends Stefan Feuerhahn · 2019-09 · Stack Overflow · on “How do I make sure the whole CompletableFuture chain is executed by an internal thread pool when designing an asynchronous Java API?”

A solution for the second requirement has been discussed by Sergey Kuksenko here [this video] and has been realized in Java 11's HttpClient implementation. The requirement is not met because it is not guaranteed that decode(response) is executed by an internal thread. If encode and sendAndReceiveAsync are completed quickly, decode could actually be executed by the caller's thread. The problem can be fixed by introducing a CompletableFuture startCf to kick-off the CF-chain. Thus the complete solution could look like the following CompletableFuture<Data> requestAsyncFixedAll(Address address) { CompletableFuture<Void> startCf = new CompletableFuture<>(); CompletableFuture<Data> dataCf = startCf.then

Cites ansjob · 2019-08 · Stack Overflow · on “Is there a performance benefit of using CompletableFuture callbacks?”

In most cases, you won't notice a difference, but if you want to be able to have a lot of concurrent asynchronous calls waiting something, you'll want to use CompletableFuture . The reason is that if you simply call get() on a regular Future the Thread and all resources associated with it become blocked until the call returns. If you have many calls your thread pool might get exhausted, or if you use a CachedThreadPool you might cause lots of threads to be created. With CompletableFuture , an object is stored on the heap which represents where the application should pick up next, as opposed to using the call stack. The guy who built the API has a talk about it over here [this video] .

Cites Denis Zavedeev · 2023-08 · Stack Overflow · on “Why does the 'execute' method of ExecutorService in applyAsync run on main thread sometimes”

Does it depend on how long it takes to complete the Supplier in supplyAsync ? This depends on whether or not the supplyAsync part has been completed before the thenApplyAsync call. Explanation Let's split the CompletableFuture chain in the testWhoCalled test for explanation. Instead of: Integer result = CompletableFuture.supplyAsync(() -> 1, firstExecutor) .thenApplyAsync(supplyResult -> supplyResult, secondExecutor) .get(); do: CompletableFuture<Integer> firstFuture = CompletableFuture.supplyAsync(() -> 1, firstExecutor); Integer result = firstFuture .thenApplyAsync(supplyResult -> supplyResult, secondExecutor) .get(); The test still fails for me sometimes. There are no changes in logic, bu