Understanding Synchronous and Asynchronous Calls in Spring Boot with @Async

This article explains the difference between synchronous and asynchronous method calls in Java, demonstrates a simple Spring Boot Task class with three time‑consuming methods, shows how to convert them to asynchronous execution using @Async and @EnableAsync, and illustrates how to coordinate completion with Future objects.

Java Architect Essentials
Java Architect Essentials
Java Architect Essentials
Understanding Synchronous and Asynchronous Calls in Spring Boot with @Async

In high‑concurrency web applications, asynchronous calls are often used to improve performance. A synchronous call executes each line sequentially, waiting for the previous line to finish; an asynchronous call proceeds without waiting for the result.

The article first presents a @Component public class Task with three methods ( doTaskOne, doTaskTwo, doTaskThree) that each sleep for a random time up to 10 seconds and print start/end messages. A JUnit test injects the Task bean and calls the three methods sequentially, producing ordered output and a total execution time equal to the sum of the three tasks.

To improve efficiency, the same Task class is modified by adding the @Async annotation to each method, turning them into asynchronous calls. For the annotation to work, the Spring Boot application class must also be annotated with @EnableAsync:

@SpringBootApplication
@EnableAsync
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

Running the unit test after this change may produce no output, partial output, or out‑of‑order output because the main thread finishes before the asynchronous tasks complete.

To reliably wait for all asynchronous tasks, the methods are changed to return Future<String> (e.g.,

public Future<String> doTaskOne() throws Exception { … return new AsyncResult<>("Task One Done"); }

). The test records a start time, invokes the three methods to obtain Future objects, and then loops until all futures report isDone(). After the loop, it records the end time and prints the total elapsed time, demonstrating a reduced overall duration due to concurrent execution.

Key takeaways: use @Async with @EnableAsync for asynchronous execution, avoid static methods for async, and use Future (or other async result types) to coordinate completion when needed.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

javabackend-developmentconcurrencyAsynchronousSpring BootAsync
Java Architect Essentials
Written by

Java Architect Essentials

Committed to sharing quality articles and tutorials to help Java programmers progress from junior to mid-level to senior architect. We curate high-quality learning resources, interview questions, videos, and projects from across the internet to help you systematically improve your Java architecture skills. Follow and reply '1024' to get Java programming resources. Learn together, grow together.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.