import org.springframework.scheduling.annotation.Async; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.util.concurrent.CompletableFuture; @RestController public class AsyncController { @Async @GetMapping("/async") public CompletableFuture<String> asyncMethod() { return CompletableFuture.supplyAsync(() -> { try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } return "Done"; }); } }
When a method is annotated with @Async in Spring Boot, it runs in a separate thread managed by Spring's task executor. The method returns immediately with a CompletableFuture, allowing the caller to continue without waiting for the method to finish.
import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import java.util.concurrent.CompletableFuture; @Service public class AsyncService { @Async public CompletableFuture<String> fetchData() { try { Thread.sleep(500); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } return CompletableFuture.completedFuture("Data Ready"); } } // Caller code (Spring-managed bean): CompletableFuture<String> future = service.fetchData(); System.out.println("Result: " + future.getNow("Not Ready"));
The getNow method returns the given default value if the CompletableFuture is not completed yet. Since the async method sleeps for 500ms and the print happens immediately, the future is not done, so it prints the default value.
The @EnableAsync annotation enables Spring's asynchronous method execution capability. Without it, @Async annotations have no effect.
import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; @Service public class MyService { @Async public void asyncTask() { System.out.println("Running async task"); } public void callAsync() { asyncTask(); } }
Spring uses proxies to intercept calls to @Async methods. When a method is called from within the same class, the proxy is bypassed, so the method runs synchronously.
Async processing frees up server threads during long-running tasks, allowing the server to handle more requests simultaneously. This improves scalability and responsiveness.