@Async — Asynchronous Method Execution in Spring Boot
Fast recall
Quick revision
Core answer
@Async enables asynchronous method execution through proxy-based interception. Spring wraps the call in a Runnable/Callable and submits it to a TaskExecutor. The method returns immediately and the actual work runs on a separate thread. The key pitfalls: self-invocation bypasses the proxy (same as @Transactional), the default executor is `SimpleAsyncTaskExecutor` which creates unbounded threads, and exceptions in `void` methods are silently lost. Configure a ThreadPoolTaskExecutor with bounded queue and CallerRunsPolicy, return CompletableFuture for callable methods, and register an AsyncUncaughtExceptionHandler for void methods.Whether the candidate understands the proxy mechanism behind `@Async` and its limitations
Calling an `@Async` method from within the same class (self-invocation), which bypasses the proxy and runs synchronously
Explain configuring a custom `ThreadPoolTaskExecutor` with bounded queue and `CallerRunsPolicy`, using `AsyncUncaughtExceptionHandler` for void methods, and `TaskDecorator` for context propagation
Interview-ready guide
Interview answer
@Async makes a method execute on a separate thread, freeing the caller to continue. Like @Transactional, it works through a proxy — which means the same self-invocation trap applies.
The proxy requirement
@Asyncworks by wrapping the bean in a proxy that submits the method to a thread pool executor- Calling
this.asyncMethod()inside the same class bypasses the proxy and runs synchronously — no error, no warning, just unexpected synchronous behavior - Fix: move the async method to a separate Spring bean and inject it
The thread pool
- Spring Boot's default async executor is
SimpleAsyncTaskExecutor, which creates a new thread for every call — not a pool - Under load, this creates hundreds of threads and exhausts heap memory
- Define a
ThreadPoolTaskExecutorbean withcorePoolSize,maxPoolSize,queueCapacity, andCallerRunsPolicyfor backpressure
Handling results and exceptions
- Return
CompletableFutureto let callers chain callbacks and handle exceptions voidreturn methods swallow exceptions silently; configureAsyncUncaughtExceptionHandlerviaAsyncConfigurerto log them
Context propagation
@Asyncdoes not propagate MDC,SecurityContext, or request-scoped beans across threads- Implement
TaskDecoratorto copy thread-local state from caller to worker
Add @EnableAsync to a @Configuration class — without it, @Async is silently ignored and every annotated method executes synchronously. In an interview, the strong answer is: `@EnableAsync` + bounded `ThreadPoolTaskExecutor` + `CallerRunsPolicy` + `CompletableFuture` returns + `TaskDecorator` for context — that's the production setup.
@Async — Asynchronous Method Execution in Spring Boot
Direct Answer
@Async enables asynchronous method execution through proxy-based interception. Spring wraps the call in a Runnable/Callable and submits it to a TaskExecutor. The method returns immediately and the actual work runs on a separate thread. The key pitfalls: self-invocation bypasses the proxy (same as @Transactional), the default executor is SimpleAsyncTaskExecutor which creates unbounded threads, and exceptions in void methods are silently lost. Configure a ThreadPoolTaskExecutor with bounded queue and CallerRunsPolicy, return CompletableFuture<T> for callable methods, and register an AsyncUncaughtExceptionHandler for void methods.
Common Mistakes & Pitfalls
Calling an @Async method from within the same class (self-invocation), which bypasses the proxy and runs synchronously
Check your understanding
Answer these without looking back at the article.
- How does `@Async` interact with `@Transactional` on the same method?
- What is `TaskDecorator` and why is it needed for `SecurityContext` and MDC?
- Why is `CallerRunsPolicy` usually the right rejection handler for an async executor?
- How would you test an `@Async` method without using `Thread.sleep`?
Related interview prep categories
1Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.