import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; @Service public class AsyncService { @Async public void asyncVoidMethod() { System.out.println("Start asyncVoidMethod"); try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } System.out.println("End asyncVoidMethod"); } }
When a method annotated with @Async returns void, Spring runs it asynchronously in a separate thread. The caller does not wait for the method to complete and does not receive any result or Future object.
import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; @Service public class AsyncService { @Async public void firstAsync() { System.out.println("First start"); try { Thread.sleep(500); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } System.out.println("First end"); } @Async public void secondAsync() { System.out.println("Second start"); try { Thread.sleep(300); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } System.out.println("Second end"); } } // In some caller bean asyncService.firstAsync(); asyncService.secondAsync();
Both methods start asynchronously almost immediately. Since secondAsync sleeps less, its end prints before firstAsync ends. The starts print in call order.
The @EnableAsync annotation on a configuration or main class activates Spring's asynchronous method execution capability.
import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; @Service public class AsyncService { @Async public void asyncMethod() { System.out.println("Async method running"); } public void callerMethod() { asyncMethod(); } }
Spring uses proxies to intercept calls to @Async methods. Calls from within the same class bypass the proxy, so the annotation has no effect.
Returning CompletableFuture from an @Async method lets the caller receive a handle to the future result, enabling non-blocking result processing.