SpringBoot asynchronous use of @Async principle and thread pool configuration

created at 09-14-2021 views: 1

Preface

In actual project development, many business scenarios need to use asynchronous to complete, such as message notification, logging, and other very commonly used can be executed asynchronously to improve efficiency, then how to use asynchronous in the Spring framework?

Steps for usage

There are generally two types of asynchronous operations, message queue MQ, and thread pool processing ThreadPoolExecutor

In the thread pool ThreadPoolTaskExecutor encapsulated by ThreadPoolExecutor provided in Spring4, @Async is directly enabled using the annotation. This annotation makes it very convenient for us to complete asynchronous operations using Spring

Configure thread pool class parameter configuration

Custom constant class

public class ConstantFiledUtil {
    public static final String AUTHORIZATION_TOKEN = "authorizationToken";
    /**
     * kmall thread pool name
     */
    public static final String KMALL_THREAD_POOL = "KmallThreadPool";

    /**
     * kmall thread name prefix
     */
    public static final String KMALL_THREAD_NAME_PREFIX = "kmall-thread-";
}

Configure thread pool

@Configuration(proxyBeanMethods = false)
@EnableAsync //Open annotation
public class KmallConfig {

  @Bean(ConstantFiledUtil.KMALL_THREAD_POOL)
    public ThreadPoolTaskExecutor FebsShiroThreadPoolTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
         //配置核心线程数
        executor.setCorePoolSize(5);
        //Configure the maximum number of threads
        executor.setMaxPoolSize(20);
        //Configure queue size
        executor.setQueueCapacity(200);
        //The idle time allowed by the thread pool maintenance thread
        executor.setKeepAliveSeconds(30);
        //Configure the name prefix of threads in the thread pool
        executor.setThreadNamePrefix(ConstantFiledUtil.KMALL_THREAD_NAME_PREFIX);
        //When the thread pool is closed, wait for all tasks to complete before continuing to destroy other beans
        executor.setWaitForTasksToCompleteOnShutdown(true);
        //Set the waiting time of the task in the thread pool, if it exceeds this time, it will be forced to be destroyed, to ensure that the application can be closed in the end, rather than being blocked
        executor.setAwaitTerminationSeconds(60);
          // rejection-policy: How to deal with new tasks when the pool has reached max size
        // CALLER_RUNS: do not perform tasks in the new thread, but by the thread where the caller is located
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //Perform initialization
        executor.initialize();
        return executor;
    }

}

Note that you need to enable asynchrony through @EnableAsync, otherwise it will be invalid

Custom thread task

public interface ILogService extends IService<Log> {

    /**
     * Paging search query log information
     * @param logParams
     * @return
     */
    IPage getSearchLogByPage(SearchLogParams logParams);

    /**
     * Save log
     *
     * @param logSubject
     */
    @Async
    void saveLog(LogSubject logSubject);
}

Add the @Async annotation to the interface or method that needs to be executed asynchronously. This method is an asynchronous method. Called in the main program, it is executed in a separate thread asynchronously.

This annotation indicates that the thread pool entered by the saveLog method is created by the KmallThreadPool method.

We can also specify the method name separately @Async("saveLogs")

In this way, when diary recording is performed, a separate thread executes each request and responds quickly, and time-consuming operations are left to the threads in the thread pool to execute asynchronously.

Summarize

  1. Methods marked with @Async annotations in Spring are called asynchronous methods. Using @Async in a spring boot application is very simple:
  2. Call the asynchronous method class or start the class with the annotation @EnableAsync
  3. Add @Async to the method that needs to be called asynchronously
    The class object of the @Async annotation method used should be a bean object managed by the Spring container;

Note that calling asynchronous methods in the same class does not take effect: the reason is that the method calls in the default class will not be intercepted by aop, that is, the caller and the callee are in the same class, and no aspect can be generated. The object is not used by the Spring container. manage. That is, the @Async method does not take effect.

Solution:

If you want to intercept calls between methods in the same class, you need to use the instance object in the spring container instead of the default this, because calls through bean instances will be intercepted by spring aop
The method used in this example: AsyncService asyncService = context.getBean(AsyncService.class); Then use this reference to call the local method to achieve the purpose of being intercepted
Note: This method can only intercept protected, default, public methods, and private methods cannot be intercepted. This is a mechanism of spring aop.

Principle analysis

There are only two return types of asynchronous methods:

  1. When the return type is void, the exception generated by the method call process will not be thrown to the caller level, and this type of exception can be caught by annotating AsyncUncaughtExceptionHandler
  2. When the return type is Future, the exception generated by the method call process will be thrown to the caller level

Note that if you do not customize the thread pool of the asynchronous method, SimpleAsyncTaskExecutor is used by default. SimpleAsyncTaskExecutor: Not a real thread pool. This class does not reuse threads. A new thread is created every time it is called. When the concurrency is large, serious performance problems will occur.

Spring asynchronous thread pool interface TaskExecutor

See the source code

@FunctionalInterface
public interface TaskExecutor extends Executor {
    void execute(Runnable var1);
}

There are many implementation classes as follows:

implementation classes

  • SimpleAsyncTaskExecutor: Not a real thread pool. This class does not reuse threads. A new thread is created every time it is called.
  • SyncTaskExecutor: This class does not implement asynchronous calls, but a synchronous operation. Only suitable for places where multi-threading is not required
  • ConcurrentTaskExecutor: The adaptation class of Executor, it is not recommended. If ThreadPoolTaskExecutor does not meet the requirements, consider using this class
  • SimpleThreadPoolTaskExecutor: is a class of Quartz's SimpleThreadPool. Thread pool is used by quartz and non-quartz at the same time, only need to use this class
  • ThreadPoolTaskExecutor: Most commonly used, recommended. Its essence is the packaging of java.util.concurrent.ThreadPoolExecutor,
Please log in to leave a comment.