5 minutes to understand - Async, the asynchronous framework of SpringBoot

Asynchronous framework

Why use asynchronous framework? Solve what problem?

In the development of spring boot, it is generally called synchronously. However, there are often special businesses that need to be processed asynchronously.
For example: register a new user, send 100 points, or place a successful order, send a push message, etc.
Why do you register new users asynchronously?

  • The first reason: fault tolerance and robustness. If there is an exception in sending points, the user registration cannot fail because of sending points;
    Because user registration is the main function and sending points is the secondary function, even if the sending of points is abnormal, the user should be prompted to register successfully, and then compensation will be made for the abnormal points.
  • The second reason: improve performance. For example, it takes 20 milliseconds to register users and 50 milliseconds to send points. If synchronous, it takes 70 milliseconds. If asynchronous, it doesn't need to wait for points, so it takes 20 milliseconds.

Therefore, asynchronous can solve two problems, performance and fault tolerance

Application examples

You only need to use the @ Async annotation to implement the asynchronous call of the method.
@Example of Async asynchronous call:
Step 1: start asynchronous task
Use @ EnableAshnc to start asynchronous tasks;
It is easy to inject this class into ioc using @ configuration;

@Configuration
@EnableAsync
public class AsyncConfiguration{    
}

Step 2: mark the asynchronous call controller layer on the method

@RestController
@Slf4j
public class TestController{
    @Autowired
    private ScoreService scoreService;
    
    @RequestMapping("/sync")
    public  String  createUser() {
        log.info("--------------Registered user--------------------");
        this.scoreService.addScore();
        return "OK";
    }
    @RequestMapping("/sync2")
    public  String  createUser2() {
        log.info("--------------Registered user 2--------------------");
        this.scoreService.addScore2();
        return "OK";
    }
}

service layer: add @ Async annotation on the method to indicate that the method is called asynchronously

@Service
@Slf4j
public class ScoreService{
    @Async
    public void addScore(){
          try{
              Thread.sleep(10000);
              log.info("Add points");          
          }  catch(Exception e){}
    }
    @Async
    public void addScore2(){
    	try{
         	Thread.sleep(10000)     
    	 }catch(Exception e){}
    }
}

@The underlying principle of Async thread pool configuration

@The Async annotation uses the SimpleAsyncTaskExecutor thread pool by default, which is not a true thread pool; Because threads are not reused and destroyed after use, a thread will be created for each call.
And distributed, resulting in a waste of resources and reducing the system, because there are two more steps of creation and destruction, which is time-consuming.
@Async annotates a variety of thread pools provided by the asynchronous framework
SimpleAsyncTaskExecutor: it is not a real thread pool. This class does not reuse threads. Each call will create a new thread.

@Async annotates a variety of thread pools provided by the asynchronous framework:

  • SimpleAsyncTaskExecutor: it is not a real thread pool. This class does not reuse threads. Each call will create a new thread.
  • SyncTaskExecutor: this class does not implement asynchronous call, but a synchronous operation.
  • ConcurrentTaskExecutor: the adapter class of Executor, which is not recommended. Consider using this class only if ThreadPoolTaskExecutor does not meet the requirements
  • ThreadPoolTaskScheduler: you can use cron expressions
  • ThreadPoolTaskExecutor: most commonly used, recommended. Its essence is to Java util. concurrent. Wrappers for ThreadPoolExecutor (jdk's own thread pool)

Implement a custom thread pool for @ Async
Step 1

@Configuraion
@EnableAsync
public class AsyncConfiguration
{
    @Bean(name="scorePoolTaskExecutor")
    public ThreadPoolTaskExecutor getScorePoolTaskExecutor(){
       //Create thread pool
         ThreadPoolTaskExecutor taskExecutor=new ThreadPoolTaskExecutor();
        //Number of core threads
        taskExecutor.setCorePoolSize(10);
        //The thread pool maintains the maximum number of threads. Threads exceeding the number of core threads will be applied only after the buffer queue is full
        taskExecutor.setMaxPoolSize(100);
        //Cache queue
        taskExecutor.setQueueCapacity(50);
        //The allowed idle time. When the idle time exceeds that of the core thread, the thread will be destroyed after the idle time arrives
        taskExecutor.setKeepAliveSeconds(200);
        //Asynchronous method internal thread name
        taskExecutor.setThreadNamePrefix("score-");
        /**
         * When the task cache queue of the thread pool is full and the number of threads in the thread pool reaches maximumPoolSize, the task rejection policy will be adopted if there are still tasks coming
         * There are usually four strategies:
         * ThreadPoolExecutor.AbortPolicy:Discard the task and throw a RejectedExecutionException exception.
         * ThreadPoolExecutor.DiscardPolicy: It also discards the task without throwing an exception.
         * ThreadPoolExecutor.DiscardOldestPolicy: Discard the task at the top of the queue and try to execute the task again (repeat this process)
         * ThreadPoolExecutor.CallerRunsPolicy: Retry adding the current task, and automatically call the execute() method repeatedly until it succeeds
         */   
         taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
         taskExecutor.initialize();
         return taskExecutor;
    }
}

Step 2: specify the thread pool name for @ Async

@Async("scorePoolTaskExecutor")
public void addScore2(){
         try {
            Thread.sleep(1000*5);
            log.info("--------------Processing integral--------------------");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
}

In real Internet project development, for high concurrency requests, the general practice is to isolate the high concurrency interface from a separate thread pool.

Keywords: Java Spring Spring Boot Multithreading

Added by cx323 on Thu, 03 Feb 2022 04:36:02 +0200