What is “asynchronous invocation”? “Asynchronous invocation” corresponds to “synchronous invocation”. Synchronous invocation means that programs are executed in a defined order. Each line of programs must wait for the completion of the previous line of programs to be executed. Asynchronous invocation refers to the sequential execution of a program without waiting for the result of the asynchronous invocation.
A synchronous invocation
Here is a simple example to get an intuitive understanding of what synchronous calls are:
Define Task class, create three processing functions to simulate three tasks, operation time is randomly selected (within 10 seconds)
@Slf4j
@Component
public class AsyncTasks {
public static Random random = new Random();
public void doTaskOne(a) throws Exception {
log.info("Start on task one.");
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
log.info("Complete Task 1, Time:" + (end - start) + "毫秒");
}
public void doTaskTwo(a) throws Exception {
log.info("Start on task two.");
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
log.info("Complete Task 2, Time:" + (end - start) + "毫秒");
}
public void doTaskThree(a) throws Exception {
log.info("Start on task three.");
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
log.info("Complete Task 3, Time:" + (end - start) + "毫秒"); }}Copy the code
In the unit test case, the Task object is injected and the three functions doTaskOne, doTaskTwo, and doTaskThree are executed in the test case.
@Slf4j
@SpringBootTest
public class Chapter75ApplicationTests {
@Autowired
private AsyncTasks asyncTasks;
@Test
public void test(a) throws Exception { asyncTasks.doTaskOne(); asyncTasks.doTaskTwo(); asyncTasks.doTaskThree(); }}Copy the code
When you execute the unit test, you see output similar to the following:
The 2021-09-11 23:19:12. 92539-922 the INFO [main] com. Didispace. Chapter75. AsyncTasks: Start to do task a 2021-09-11 23:19:17. 788 INFO 92539 - [the main] com. Didispace. Chapter75. AsyncTasks: To complete the task, a time-consuming: 4865 milliseconds 23:19:17 2021-09-11. 92539-788 INFO. [the main] com didispace. Chapter75. AsyncTasks: Start doing task 2 2021-09-11 23:19:24. 851 INFO 92539 - [the main] com. Didispace. Chapter75. AsyncTasks: To complete the task two, time-consuming: 7063 milliseconds 23:19:24 2021-09-11. 92539-851 the INFO [main] com. Didispace. Chapter75. AsyncTasks: Start doing task three 23:19:26 2021-09-11. 928 INFO 92539 - [the main] com. Didispace. Chapter75. AsyncTasks: to complete the task 3, time-consuming: 2076 millisecondsCopy the code
DoTaskOne, doTaskTwo, and doTaskThree have been executed sequentially.
The asynchronous call
Although the above synchronous invocation successfully executed the three tasks, it can be seen that the execution time is relatively long. If there is no dependency between the three tasks and they can be executed concurrently, the execution efficiency of synchronous invocation is relatively poor. Therefore, asynchronous invocation can be considered for concurrent execution.
In Spring Boot, we can simply change a synchronous function to an asynchronous function by using the @async annotation, and change the Task class to the following mode:
@Slf4j
@Component
public class AsyncTasks {
public static Random random = new Random();
@Async
public void doTaskOne(a) throws Exception {
log.info("Start on task one.");
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
log.info("Complete Task 1, Time:" + (end - start) + "毫秒");
}
@Async
public void doTaskTwo(a) throws Exception {
log.info("Start on task two.");
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
log.info("Complete Task 2, Time:" + (end - start) + "毫秒");
}
@Async
public void doTaskThree(a) throws Exception {
log.info("Start on task three.");
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
log.info("Complete Task 3, Time:" + (end - start) + "毫秒"); }}Copy the code
In order for the @async annotation to work, you also need to configure @enableAsync in the Spring Boot main program, as follows:
@EnableAsync
@SpringBootApplication
public class Chapter75Application {
public static void main(String[] args) { SpringApplication.run(Chapter75Application.class, args); }}Copy the code
At this point, you can run unit tests repeatedly, and you may encounter different results, such as:
-
There is no task-related output
-
There are partial task-specific outputs
-
Out-of-order task-related output
-
The reason is that the doTaskOne, doTaskTwo, and doTaskThree functions are executed asynchronously. After the main program is called asynchronously, the main program does not care whether the execution of these three functions is complete. Because there is no other content to be executed, the program will automatically end, resulting in incomplete or no output task related content.
Note: Do not define @async functions as static, so asynchronous calls do not take effect
An asynchronous callback
In order for doTaskOne, doTaskTwo, and doTaskThree to complete properly, suppose we need to count the total time required for the concurrent execution of the three tasks. We need to record the time and calculate the result after all the three functions are completed.
So how do we determine if the above three asynchronous calls have completed? We need to use CompletableFuture
to return the result of the asynchronous call, like modifying the doTaskOne function as follows:
@Async
public CompletableFuture<String> doTaskOne(a) throws Exception {
log.info("Start on task one.");
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
log.info("Complete Task 1, Time:" + (end - start) + "毫秒");
return CompletableFuture.completedFuture("Mission one complete.");
}
Copy the code
After modifying the other two asynchronous functions as described above, let’s modify the test case so that the test does something else after waiting for three asynchronous calls.
@Test
public void test(a) throws Exception {
long start = System.currentTimeMillis();
CompletableFuture<String> task1 = asyncTasks.doTaskOne();
CompletableFuture<String> task2 = asyncTasks.doTaskTwo();
CompletableFuture<String> task3 = asyncTasks.doTaskThree();
CompletableFuture.allOf(task1, task2, task3).join();
long end = System.currentTimeMillis();
log.info("All tasks completed, total time:" + (end - start) + "毫秒");
}
Copy the code
See what changes we’ve made:
- Record the start time at the beginning of the test case
- Returns when three asynchronous functions are called
CompletableFuture<String>
Type - through
CompletableFuture.allOf(task1, task2, task3).join()
Implement blocking until all three asynchronous tasks are finished - After all three tasks are complete, calculate the total time required for the concurrent execution of the three tasks based on the end time and start time.
Run the unit test above and see the following results:
The 2021-09-11 23:33:38. 95891-842 the INFO/task - 3 com. Didispace. Chapter75. AsyncTasks: Start doing task three 23:33:38 2021-09-11. 842 INFO - 95891 [task - 2] com. Didispace. Chapter75. AsyncTasks: Start task two 23:33:38 2021-09-11. 95891-842 the INFO] [task - 1 com. Didispace. Chapter75. AsyncTasks: Began to do the 2021-09-11 23:33:45 task. The 95891-155 the INFO/task - 2 com. Didispace. Chapter75. AsyncTasks: To complete the task two, time-consuming: 6312 milliseconds 23:33:47 2021-09-11. 95891-308 the INFO/task - 3 com. Didispace. Chapter75. AsyncTasks: To complete the task 3, time-consuming: 8465 milliseconds 23:33:47 2021-09-11. 95891-403 the INFO] [task - 1 com. Didispace. Chapter75. AsyncTasks: To complete the task, a time-consuming: 8560 milliseconds 23:33:47 2021-09-11. 95891-404 the INFO [main] C.D.C. hapter75. Chapter75ApplicationTests: The total time for all tasks to complete: 8590 msCopy the code
As you can see, by making asynchronous calls, tasks one, two, and three execute concurrently, effectively reducing the total running time of the program. Spring Boot 2.x Basic Tutorial , welcome to collect and forward! If you encounter difficulties in learning? You can join our Spring technology exchange group, participate in exchange and discussion, better learning and progress!
Code sample
For the complete project of this article, see the chapter7-5 project in the 2.x directory of the warehouse below:
- Github:github.com/dyc87112/Sp…
- Gitee:gitee.com/didispace/S…
If you found this article good, welcomeStar
Support, your attention is my motivation!
Welcome to pay attention to my public account: program ape DD, share the outside can not see the dry goods and thinking!