场景:使用spring框架自带的定时注解来实现定时任务A,定时任务B
需求:定时任务A的每次任务启动卡死,不能影响下次定时任务的触发,更不能影响定时任务B的执行
问题:spring框架自带的定时,定时任务开启成功,但所有的任务都是在同一个线程池中的同一个线程来完成的。在实际开发过程中,我们当然不希望所有的任务都运行在一个线程中,此时需要各个定时任务是相互独立的。
1.定时任务A和定时任务B是相互独立的,但是定时任务A的某个任务卡死是会影响A的下一个任务出发的,每一个任务都起一条线程去执行,要求必须每个执行完毕后才能再次执行,所以不能开启异步执行
/**
* 实现SchedulingConfigurer ,重写configureTasks 用多线程
*/
@Component
public class SpringCornTask implements SchedulingConfigurer {
@Autowired
@Qualifier("updateAsyncExecutor")
ThreadPoolTaskScheduler threadPoolTaskScheduler;
//所有加了注解@Scheduled都是用的同一个线程池threadPoolTaskScheduler的线程,同时线程的名字updateAsyncExecutor-
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(threadPoolTaskScheduler);
}
}
/**
* 创建定时任务线程池
*/
@Bean("updateAsyncExecutor")
public ThreadPoolTaskScheduler updateAsyncExecutor() {
ThreadPoolTaskScheduler executor = new ThreadPoolTaskScheduler();
executor.setPoolSize(3);
executor.setThreadNamePrefix("updateAsyncExecutor-");
//用来设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean
executor.setWaitForTasksToCompleteOnShutdown(true);
//该方法用来设置线程池中任务的等待时间,如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住。
executor.setAwaitTerminationSeconds(9000);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
return executor;
}
/**
* 定时任务A
*/
@Scheduled(cron = "0 0 0/4 * * ?")
public void updateRecord() throws IOException {
log.info("开始执行定时任务===" + new Date() + "===" + Thread.currentThread().getName());
}
2.实现结果是定时任务A和定时任务B是相互独立的,而且定时任务A的某个任务卡死是不会影响A的下一个任务出发的,同时担心A和B如果共用同一个线程池,如果任务A卡死,不断起线程,不断卡死,会把线程池任务占用完毕,最终会影响到B,更何况A和B的执行频率差异很大
/**
* 创建B的线程池
*/
@Bean("cleanAsyncExecutor")
public ThreadPoolTaskScheduler cleanAsyncExecutor() {
ThreadPoolTaskScheduler executor = new ThreadPoolTaskScheduler();
executor.setPoolSize(3);
executor.setThreadNamePrefix("cleanAsyncExecutor-");
executor.setWaitForTasksToCompleteOnShutdown(true);
//该方法用来设置线程池中任务的等待时间,如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住。
executor.setAwaitTerminationSeconds(9000);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
return executor;
}
//同理,创建A的线程池
.................
/**
* 定时任务A,同时开启异步,指定线程池updateAsyncExecutor
*/
@Async("updateAsyncExecutor")
@Scheduled(cron = "0 0 0/5 * * ?")
public void updateCompareDataRecord() throws IOException {
log.info("开始执行定时任务A===" + new Date() + "===" + Thread.currentThread().getName());
}
/**
* 定时任务B,同时开启异步,指定线程池updateAsyncExecutor
*/
@Async("cleanAsyncExecutor")
@Scheduled(cron = "0 0 0 1/1 * ?")
public void cleanDataRecord() throws IOException {
log.info("开始执行定时任务AB===" + new Date() + "===" + Thread.currentThread().getName());
}
可以参考:spring scheduled单线程和多线程使用过程中的大坑!!不看到时候绝对后悔!! - hellodev - 博客园 (cnblogs.com)