SpringBoot annotation @ Async usage and precautions

Keywords: Spring Boot

1, How to use @ Async

1. Learn about @ Async

In java applications, in most cases, interactive processing is realized by means of synchronization; However, when dealing with the interaction with third-party systems, it is easy to cause slow response. Before, most of them used multithreading to complete such tasks. In fact, in spring   After 3.x, @ Async has been built in to perfectly solve this problem. This article will introduce the usage of @ Async.

    

2. What is an asynchronous call?

    Before explaining asynchronous invocation, let's look at the definition of synchronous invocation; Synchronization is the sequential execution of the whole processing process. When each process is completed, the results are returned. Asynchronous calling is just sending the called instruction, and the caller does not need to wait for the called method to be fully executed; Instead, continue with the following process.

      For example, in a call, you need to call three process methods a, B and C in sequence; If they are all synchronous calls, they need to be executed in sequence before the process is completed; If B is an asynchronous calling method, after calling A after executing the B, it does not wait for B to complete. Instead, the execution starts calling C. After C is executed, it means that the process is finished.

 

3. Conventional asynchronous call processing

    In Java, when dealing with similar scenarios, it is generally based on creating an independent thread to complete the corresponding asynchronous call logic, through the execution process between the main thread and different threads, so that after the independent thread is started, the main thread continues to execute without stagnation.

 

4. @ Async introduction

    In Spring, the method based on @ Async annotation is called asynchronous method; When these methods are executed, they will be executed in a separate thread. The caller can continue other operations without waiting for it to complete.

 

5. How to enable @ Async in Spring

      Enabling method based on SpringBoot configuration: enable asynchronous annotation support on the startup class of SpringBoot   @ EnableAsync

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

 

The enabling method based on XML configuration file is configured as follows:

<task:executor id="myexecutor" pool-size="5"  />
<task:annotation-driven executor="myexecutor"/>

 

6. Call based on @ Async with no return value (use this method more often)

 

@Async  //Annotation use
public void asyncMethodWithVoidReturnType() {
    System.out.println("Start a new thread named: " + Thread.currentThread().getName());
}

 

  7. Call with return value based on @ Async

 

@Async
public String asyncMethodWithReturnType() {
    System.out.println("Start a new thread named: " + Thread.currentThread().getName());
    try {
        Thread.sleep(5000);
        return new String("hello world !!!!");
    } catch (InterruptedException e) {
    }
    return null;
}

 

 

2, Precautions for using @ Async

In the actual project, we can execute some code fragments or functions that take a long time asynchronously, so that the overall process will not be affected. For example, I need to upload some files in a user request, but the time-consuming of uploading files will be relatively long. At this time, if the success of uploading files does not affect the main process, I can asynchronize the operation of uploading files. A common way in spring boot is to encapsulate the code fragments to be executed asynchronously into a function, Then use @ Async annotation in the function header to realize the asynchronous execution of code. Let me repeat it!

First, create a new spring boot project

package com.example.demo;

@SpringBootApplication
@EnableAsync
public class DemoApplication {

    public static void main(String[] args){
        SpringApplication.run(DemoApplication.class, args);  
    }
}

 

 

Create a new Task class to put three asynchronous tasks dotaskane, doTaskTwo and doTaskThree:

package com.example.demo.service;

import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.util.Random;

@Component
public class Task {
    public static Random random =  new Random();

    @Async
    public void doTaskOne() throws InterruptedException {
        System.out.println("Start task one");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        System.out.println("Completing task 1 takes:"+ (end - start));
    }

    @Async
    public void doTaskTwo() throws Exception {
        System.out.println("Start task two");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        System.out.println("Completing task 2 takes:" + (end - start) + "millisecond");
    }

    @Async
    public void doTaskThree() throws InterruptedException {
        System.out.println("Start task three");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        System.out.println("Completing task 3 takes:" + (end - start) + "millisecond");
    }
}

 

  In order to complete the execution of these three methods, we need to add a delay to the last line of the unit test case, otherwise the asynchronous task will not be completed when the function exits.

Test on the main startup class to test the execution process of the three methods:

package com.example.demo;


import com.example.demo.service.UseAsync;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication
@EnableAsync
public class DemoApplication {

    public static void main(String[] args) throws Exception {
        ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
        Task task = context.getBean("task", Task.class);
        task.doTaskOne();
        task.doTaskTwo();
        task.doTaskThree();
        Thread.sleep(10000);
        System.out.println("Blood devil");
    }

}

 

  Look at my random tests:

   

 

 

  We see that the three tasks are indeed executed asynchronously. Let's look at the wrong usage.

 

Write a method that calls these @ Async annotated methods in the class that calls these asynchronous methods.

package com.example.demo.service;


import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.util.Random;

@Component
public class Task {

    public static Random random =  new Random();

    public void useAsync() throws Exception {
        doTaskOne();
        doTaskTwo();
        doTaskThree();
    }

    @Async
    public void doTaskOne() throws InterruptedException {
        System.out.println("Start task one");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        System.out.println("Completing task 1 takes:"+ (end - start));
    }

    @Async
    public void doTaskTwo() throws Exception {
        System.out.println("Start task two");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        System.out.println("Completing task 2 takes:" + (end - start) + "millisecond");
    }

    @Async
    public void doTaskThree() throws InterruptedException {
        System.out.println("Start task three");
        long start = System.currentTimeMillis();
        Thread.sleep(random.nextInt(10000));
        long end = System.currentTimeMillis();
        System.out.println("Completing task 3 takes:" + (end - start) + "millisecond");
    }
}

 

This method is then called in the startup class

package com.example.demo;


import com.example.demo.service.Task;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication
@EnableAsync
public class DemoApplication {

    public static void main(String[] args) throws Exception {
        ApplicationContext context = SpringApplication.run(DemoApplication.class, args);
        Task task = context.getBean("task", Task.class);
        task.useAsync();
        Thread.sleep(5000);
        System.out.println("Blood devil");
    }

}

 

Then let's take a look at the implementation results of this method: (experiment several times)

    

 

  

  It can be seen that these methods are not executed asynchronously, so the method called @Async modified in the class is not executed asynchronously in the class, so the @Async method is placed in a separate class as far as possible, instead of being crowded into redundant code.

 

   

 

Posted by optimus on Thu, 02 Dec 2021 23:52:30 -0800