Springboot's @Async asynchronous scheduled task custom thread pool

在应用中经常会遇到定时执行任务的需求,这时采用异步的方式开启一个定时任务,通常引用@Async注解,但直接使用会有风险,当我们没有指定线程池时,会默认使用其Spring自带的 SimpleAsyncTaskExecutor 线程池,会不断的创建线程,当并发大的时候会严重影响性能。

1. Introduction to @Async

@Async is an annotation. Its function is that the class or method with this annotation can perform tasks asynchronously. When this annotation is added to a method, it means that the method is an asynchronous method. When it is added to a class, it means that the method is an asynchronous method. All methods in the class are asynchronous methods.
When using @Async, if you do not specify a specific thread pool name, the default thread pool SimpleAsyncTaskExecutor is used. The default configuration of the thread pool is (in TaskExecutionProperties):

  • Number of core threads: 8
  • Capacity: Integer.MAX_VALUE
  • Maximum number of threads: Integer.MAX_VALUE
  • Idle thread survival time: 60s
  • Allow core thread timeouts: true

It can be seen from the above configuration that when the amount of concurrency is large, threads will be created without limit. When the number of threads reaches a certain level, the corresponding performance will be affected. Therefore, when using the @Async annotation, it is best to use a custom thread pool, that is, add the name of the custom thread pool to the annotation.

2. Turn on asynchronous

Add @EnableAsync to the startup class to enable asynchronous, similar to the following:

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

3. Configure a custom thread pool

The configuration class is similar to the following:

@EnableAsync
@Configuration
public class ThreadPoolConfig {
    /**
     * 线程池任务执行器
     * @return
     */
    @Bean
    public Executor taskExecutor() {
    	// 创建线程池
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 设置核心池大小
        executor.setCorePoolSize(5); 
        // 设置最大池大小,只有在缓冲队列满了之后才会申请超过核心线程数的线程
        executor.setMaxPoolSize(10); 
        // 设置队列容量
        executor.setQueueCapacity(100); 
        // 设置保持活动秒数,当超过了核心线程数之外的线程在空闲时间到达之后会被销毁
        executor.setKeepAliveSeconds(60); 
        // 设置线程名称前缀
        executor.setThreadNamePrefix("myThread-"); 
        // 设置拒绝的执行处理策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }
}

There are generally four types of rejection strategies:

ThreadPoolExecutor.AbortPolicy: Discard the task and throw RejectedExecutionException.
ThreadPoolExecutor.DiscardPolicy: also discards tasks, but does not throw an exception.
ThreadPoolExecutor.DiscardOldestPolicy: Discard the front task of the queue, and then try to execute the task again (repeat this process)
ThreadPoolExecutor.CallerRunsPolicy: Retry adding the current task, Automatically call the execute() method repeatedly until successful
Note: @EnableAsync needs to be added to the startup class or configuration class to enable asynchronous.
The operating mechanism of the thread pool is as follows:
Insert image description here

4. @Async specifies the thread pool

Just specify the thread pool name directly in the @Async annotation, similar to the following:

@Async("taskExecutor")
    public void asyncTask() {
        // 逻辑代码...
        log.info("当前线程为:" + Thread.currentThread().getName());
    }

5. Possible reasons for @Async failure

  • The startup class or thread pool configuration class is not annotated with @EnableAsync
  • Do not call the method and the @Async method in the same class
  • The return value of the @Async method can only be void and Future
  • Methods modified with @Async cannot be modified with static
  • The method decorated with @Async must be public

Guess you like

Origin blog.csdn.net/leijie0322/article/details/132448308