The use of Spring @Async annotation

Premise of use

  1. If there is an asynchronous method in the current class a.class and @ Async is used, it must be called by other classes (such as b.class), not by itself (a.class);
  2. The method must be public with no return value, that is:

        @Async
        public void asyncMethod(){
            
        }

Need attention

  1. When used with transactions, @ Transactional annotation is used on the method calling the asynchronous method.
    a.class

        @Async
        public void asyncMethod(){
            
        }

    b.class

        @Transactional
        public void fun(){
            //...
            a.asyncMethod();
            //...
        }

    There will be a problem with the transaction at this time, because a will start a new thread to execute asyncMethod(), so a and fun() are not a transaction, which will cause data inconsistency.

2. Need to configure thread pool for asynchronous
as follows

package com.fanneng.spring.config;

import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;

/**
 * Created by feifan.gou@gmail.com on 2019/11/29 20:00.
 */
@Configuration
@EnableAsync
public class ThreadPoolConfig {

    @Autowired
    private ThreadPoolProperty poolProperty;

    @Bean
    public ThreadPoolTaskExecutor taskExecutor() {

        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        /* Maximum threads */
        executor.setMaxPoolSize(poolProperty.maxPoolSize);
        /* Number of core threads */
        executor.setCorePoolSize(poolProperty.corePoolSize);
        /* Maximum queue length */
        executor.setQueueCapacity(poolProperty.queueCapacity);
        /* Thread name prefix */
        executor.setThreadNamePrefix(poolProperty.threadNamePrefix);
        /* Refusal strategy */
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }

    @Getter
    @Setter
    @Configuration
    @ConfigurationProperties(prefix = "executor.thread.pool")
    public static class ThreadPoolProperty {

        private int corePoolSize;
        private int maxPoolSize;
        private int queueCapacity;
        private String threadNamePrefix;
    }
    /* Rejection policy description (how to handle new tasks when the pool has reached max size):
     * ThreadPoolExecutor.AbortPolicy:Discard the task and throw a RejectedExecutionException exception.
     * ThreadPoolExecutor.DiscardPolicy: The task is also discarded, but no exception is thrown.
     * ThreadPoolExecutor.DiscardOldestPolicy: Discard the task at the top of the queue and retry the task (repeat the process)
     * ThreadPoolExecutor.CallerRunsPolicy: The task is processed by the calling thread
     */
}
Note when injecting ThreadPoolTaskExecutor

The method name in public ThreadPoolTaskExecutor taskExecutor() defaults to taskExecutor, which means that the bean name is also taskExecutor. When @ Async is used, the thread in the thread pool will be used by default. If other names are used, that is, the bean is another name, the thread pool name needs to be specified when @ Async is used. For example, the bean name is a Syncexecutor, when using @ Async, it should be

       @Async("asyncExector")
       public void asyncMethod(){
           
       }

Otherwise, SimpleAsyncTaskExecutor will be used by default.

Attach several common implementations of task executor in spring

Name Characteristic
SimpleAsyncTaskExecutor There is no maximum thread number setting for each new thread request. It is not a real thread pool. This class does not reuse threads. Each call will create a new thread. -- [1]
SyncTaskExecutor It is not an asynchronous thread. SyncTaskExecutor can be used for synchronization, but this is not a thread pool, because it is still executing in the original thread. This class does not implement asynchronous call, but a synchronous operation.
ConcurrentTaskExecutor Adapter class of Executor, not recommended. Consider using this class only if the ThreadPoolTaskExecutor does not meet the requirements.
SimpleThreadPoolTaskExecutor Listen to Spring's lifecycle callbacks and be compatible with the components of quartz. It is a class of SimpleThreadPool of quartz. The thread pool is used by both quartz and non quartz, so this class is needed.
ThreadPoolTaskExecutor The most commonly used. The jdk version is required to be greater than or equal to 5. The configuration of thread pool can be modified in program rather than xml. Its essence is the packaging of java.util.concurrent.ThreadPoolExecutor.

Tags: Java Spring Lombok JDK

Posted on Wed, 04 Dec 2019 18:45:11 -0500 by Jude