use of CompletableFuture.supplyAsync and CompletableFuture.completedFuture within Async annotation in spring boot
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.
Introduction
When using @Async in Spring Boot, return CompletableFuture.completedFuture(result) — not CompletableFuture.supplyAsync(). The @Async annotation already runs the method on a separate thread managed by Spring's executor. Using supplyAsync() inside an @Async method spawns a second thread (from ForkJoinPool), which is redundant and wastes resources. completedFuture() wraps the already-computed result in a CompletableFuture without creating another thread, which is the correct pattern.
The Wrong Way: supplyAsync Inside @Async
What happens: Spring runs getUser() on thread-1 (from the async executor). Inside, supplyAsync() submits the lambda to thread-2 (from ForkJoinPool). Thread-1 returns immediately with an incomplete future, and thread-2 does the actual work. This wastes thread-1 entirely.
The Right Way: completedFuture Inside @Async
Spring runs getUser() on its async thread pool. The method does the work, then wraps the result in a CompletableFuture that is immediately complete. The caller gets the future and can chain operations on it.
Setting Up @Async in Spring Boot
Calling @Async Methods
When supplyAsync IS Appropriate
Use supplyAsync when you are NOT using @Async — i.e., in regular synchronous methods where you want to explicitly run code on another thread:
Error Handling
Decision Matrix
| Scenario | Use |
@Async method returning a result | CompletableFuture.completedFuture(result) |
No @Async, need background execution | CompletableFuture.supplyAsync(supplier, executor) |
@Async method returning nothing | void return type (or CompletableFuture<Void>) |
@Async method with error | CompletableFuture.failedFuture(exception) (Java 9+) |
Common Pitfalls
- Using
supplyAsyncinside@Async: This creates two threads for one task. The@Asyncthread sits idle whilesupplyAsyncruns on aForkJoinPoolthread. UsecompletedFutureinstead — the@Asyncmethod is already running asynchronously. - Calling
@Asyncmethods from the same class: Spring's@Asyncworks through proxying. Calling an@Asyncmethod from another method in the same class bypasses the proxy and runs synchronously. Extract the async method to a separate@Servicebean. - Not configuring a thread pool: Without
@EnableAsyncand a custom executor, Spring usesSimpleAsyncTaskExecutorwhich creates a new thread per call with no pooling or queueing. Always configure aThreadPoolTaskExecutorwith bounded pool size and queue capacity. - Forgetting
@EnableAsync: The@Asyncannotation does nothing without@EnableAsyncon a configuration class. The method runs synchronously and the caller receives an already-completed future, which looks correct in tests but defeats the purpose. - Using
supplyAsync()without specifying an executor:CompletableFuture.supplyAsync(supplier)uses the commonForkJoinPool, which is shared across the JVM. Blocking I/O operations (database queries, HTTP calls) on the common pool starve CPU-bound tasks. Always pass a custom executor:supplyAsync(supplier, myExecutor).
Summary
- Use
CompletableFuture.completedFuture(result)inside@Asyncmethods — the async threading is already handled by Spring - Use
CompletableFuture.supplyAsync(supplier, executor)only in non-@Asyncmethods where you need explicit background execution - Always configure
@EnableAsyncwith aThreadPoolTaskExecutorto control pool size and behavior - Never call
@Asyncmethods from within the same class — the proxy is bypassed and the method runs synchronously - Always pass a custom executor to
supplyAsyncto avoid blocking the sharedForkJoinPool
Related reading
- Use of return in deferred computation in Ocaml Async
- Use Powershell's BeginInvoke and EndInvoke in async way
- Using a coroutine as decorator
- Using a global dictionary with threads in Python
- Use of instanceof in Java
- Use of Java's Collections.singletonList?
- Using a global variable with a thread
- Using a GPU both as video card and GPGPU

OOD Fundamentals
Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.