springboot: will @ Async execute asynchronously when using nested asynchronous annotations

1, Introduction

In the previous article[ springboot: those pits that use asynchronous annotation @ Async >The incorrect usage of using @ Async annotation to obtain task execution results is introduced in. Today, let's share another common error.

2, Code demonstration

Here is the code of my controller,

package com.atssg.controller;

import com.atssg.service.MyAsyncService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RequestMapping("/sync/")
@RestController
public class SyncController2 {
    @Autowired
    private MyAsyncService syncService;

    @GetMapping("/test2")
    public String test2() {
        return syncService.syncMethod("hello world");
    }
}

In the controller, we call the service layer syncMethod method. Let's look at the definition of the method.

package com.atssg.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
@Slf4j
@Service
public class MyAsyncService {
    @Autowired
    private SyncService syncService;
    public String syncMethod(String str) {
        String result = null;
        try {
            log.info("start,{}",System.currentTimeMillis());
            //Call the method4 method, in which another asynchronous method will be called by the bridge sleeve
            Future<String> futureResult = syncService.method4(str);
            result = futureResult.get();
            log.info("end:{}",System.currentTimeMillis());
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
        return result;
    }
}

Method4 method is an asynchronous method. Another asynchronous method will be called inside the method. See the definition of method4 method below,

/**
     * Call another asynchronous method
     *
     * @param str
     * @return
     * @throws InterruptedException
     */
    public Future<String> method4(String str) throws InterruptedException {

        //method4 sleep for 10s
        Thread.sleep(1000 * 10);
        //Call another asynchronous method
        method1(str);
        return new AsyncResult<>(str);
    }

Let's look at the method1 method,

public Future<String> method1(String str) throws InterruptedException {
        Thread.sleep(1000 * 10);
        return new AsyncResult<>(str);
    }

This method is also sleep for 10s. In addition, both methods are asynchronous methods. If you have a small partner, you will wonder how to not mark asynchronous annotation @Async. This is because the annotation can be used in methods or classes. As mentioned in the previous article, I don't know if the small partner still remembers it. If you don't know, you can see the definition of annotation again. The following is my class. Generally speaking,

Do you see, I marked @ Async on the class, which works for all methods in the class, that is, all methods are asynchronous.

According to normal logic, method4 and method1 are asynchronous methods, and the two methods are all sleeping 10s. Then the result of asynchronous execution should be 10s multipoint. But here is method1 in method4, that is nested call, then what the result will be like. Look at the execution results,

Are you surprised to see the execution result? The execution time is about more than 20s. Those who don't believe in it can execute several times. It turns out that they are all more than 20s. Why? It shouldn't be more than 10s. Is asynchronous execution invalid

3, Summary

Calling another asynchronous method in asynchronous method causes asynchronous execution failure, that is, the execution result above, so do not call asynchronous method in asynchronous method to achieve the purpose of asynchronous execution. Some friends will ask why. Let's start with the asynchronous principle. The asynchronous principle is implemented through agents. More content is welcome to pay attention to the next episode.

Keywords: Java Database Spring Spring Boot Programmer

Added by keegan on Sun, 19 Dec 2021 19:20:15 +0200