springboot之@Async异步定时任务自定义线程池

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

1、@Async简介

@Async是一个注解,其作用就是加上该注解的类或方法能够异步执行任务,该注解添加到方法上时,表示该方法是异步方法,添加到类上时,表示该类中的所有方法都是异步方法。
当在使用@Async时,如果不指定具体的线程池名称,那么其使用的是默认线程池SimpleAsyncTaskExecutor。而该线程池的默认配置为(在TaskExecutionProperties中):

  • 核心线程数:8
  • 容量:Integer.MAX_VALUE
  • 最大线程数:Integer.MAX_VALUE
  • 空闲线程存活时间:60s
  • 允许核心线程超时:true

由上面的配置可知在并发量很大的情况下,其会没有限制的创建线程,当线程数量到达一定程度之后,就会影响相应的性能了。因此,在使用@Async注解时,最好使用自定义线程池,也就是在注解中添加自定义线程池的名字。

2、开启异步

启动类添加@EnableAsync开启异步,类似如下:

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

3、配置自定义线程池

配置类类似如下:

@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;
    }
}

拒绝策略通常有四种:

ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:重试添加当前的任务,自动重复调用 execute() 方法,直到成功
注:启动类或配置类需要加上@EnableAsync,开启异步。
线程池的运行机制如下:
在这里插入图片描述

4、@Async指定线程池

在@Async注解中直接指定线程池名称即可,类似如下:

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

5、@Async失效可能原因

  • 启动类或线程池配置类没加@EnableAsync注解
  • 调用方法和@Async方法不要在一个类中
  • @Async方法的返回值只能是void和Future
  • @Async修饰的方法不能被static修饰
  • @Async修饰的的方法必须是public

猜你喜欢

转载自blog.csdn.net/leijie0322/article/details/132448308