Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchPC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11To run a Spring method asynchronously, enable annotation processing with @EnableAsync, then mark a method on a Spring bean with @Async. Spring submits an intercepted call to a TaskExecutor, so the caller can continue without waiting for the method to finish. The crucial detail is that, by default, interception happens through a Spring proxy: calling an @Async method from another method on the same object does not make that call asynchronous.
Enable asynchronous method execution
@Async marks a method for asynchronous invocation, but the annotation alone does not activate the feature. Add @EnableAsync to a configuration class in the application context:
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
@Configuration
@EnableAsync
public class AsyncConfig {
}
Spring’s annotation-driven support then intercepts eligible calls and submits their work to a TaskExecutor. Async methods can accept ordinary method arguments; the call is asynchronous, not the preparation or evaluation of the arguments at the call site.
Put the call across a Spring proxy
In the default proxy advice mode, Spring intercepts calls made through its proxy. A call from one method to another method on the same instance—often called self-invocation—does not pass through that proxy. Consequently, an inner method annotated with @Async runs as a regular synchronous call in this situation.
#1 Best Overall
Spring’s reference documentation states: “The default advice mode for processing @Async annotations is proxy which allows for interception of calls through the proxy only.” See the Spring Framework reference on asynchronous method execution.
A straightforward fix is to put the async method on a separate Spring-managed bean and call it through that bean’s injected proxy:
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@Service
public class ReportWorker {
@Async
public void generateReport(String reportId) {
// Perform the work
}
}
@Service
public class ReportService {
private final ReportWorker reportWorker;
public ReportService(ReportWorker reportWorker) {
this.reportWorker = reportWorker;
}
public void start(String reportId) {
reportWorker.generateReport(reportId);
}
}
Another interception mode may be appropriate for some applications, but it is not the default; check the documentation for the Spring Framework version in use before changing modes.
Choose an executor deliberately
Async work runs on a Spring TaskExecutor. The @EnableAsync API describes the executor lookup order as a unique TaskExecutor, then an Executor bean named taskExecutor, with SimpleAsyncTaskExecutor as the fallback if neither can be resolved. The fallback may not suit an application’s workload, so configure and validate executor behavior rather than relying on an implicit default.
Free tools Windows power users keep installed
One-click scans. No signup required.
Rank #3
For application-wide customization, implement AsyncConfigurer and provide the executor. To select a particular executor for one method, use its bean name or qualifier in the annotation, for example @Async("otherExecutor"). The available options and exact API details can vary by Spring Framework version; consult the current @EnableAsync API and the application’s matching reference documentation.
There is no universal pool size or performance threshold prescribed by this guidance. Choose executor behavior based on the application’s concurrency needs and measurements.
Rank #4
Select a return type based on the caller’s needs
| Return type | Use it when | What the caller gets |
|---|---|---|
void |
The caller does not need a result or completion handle. | No value or future is returned to the caller. |
Future |
The caller needs a result or a handle to retrieve it later. | A future whose result can be obtained after doing other work. |
CompletableFuture |
The caller needs a result and wants to compose follow-on work. | A future supporting composition; failures can be observed through the returned future. |
Use a future-returning contract when the caller must retrieve the result or observe task completion. With a void method, the caller has no returned handle for the outcome.
Handle exceptions according to the return type
For a method returning Future or CompletableFuture, execution failures are observed through the returned future. Arrange for the caller to inspect or handle that future; simply starting the work does not mean its eventual result or failure has been dealt with.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Clear out junk files and repair common Windows errors3Scan for outdated or missing drivers - takes under a minuteBest Value
A void async method cannot send its execution exception back to its caller. By default, uncaught exceptions from such methods are logged. If logging alone is insufficient, configure an AsyncUncaughtExceptionHandler through AsyncConfigurer or the supported XML configuration. See the AsyncConfigurer API and AsyncUncaughtExceptionHandler API.
Do not apply @Async directly to a lifecycle callback
@Async cannot be used in conjunction with callbacks such as @PostConstruct. If initialization must trigger asynchronous work, use a separate initializer bean to invoke the async method after initialization, as described in the Spring Framework reference.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

