项目场景:
在系统中,通过@Scheduled创建了10几个定时任务,对系统数据进行统计、数据清理、缓存初始化等操作。
问题描述
在系统中,通过@Scheduled方式创建了10多个定时任务,定义的cron表达式有几个是cron = "0 0/5 * * * ?",有些是0 */30 * * * ?。有个定时任务是每5分钟对mongodb存储的API接口调用情况按天、小时、日等维度做统计数据。系统上线一段时间之后,API调用统计经常不是每隔5分钟执行,导致统计数据不准
原因分析:
统计的定时任务增加打印日志,打印每次进入定时任务的时间,定位哪个时间段没有执行任务。通过打印日志,发现xx:30分钟左右的时候,经常不会执行,怀疑是0 */30 * * * ?对它有影响。
经过排查,发现有一个在30分执行的定时任务,执行时间需要几分钟。通过查资料,知道@Scheduled定时任务默认使用单线程模式。 30分钟的时候,线程被阻塞,导致一些任务到点不执行。
@Scheduled定时任务默认使用单线程模式。 系统中多于1个定时任务,是会排队执行,如果有任务执行时间长,会阻塞后面任务的执行。
解决方案:
给严格要求到点执行的定时任务,指定特定的线程池。例如下面的例子
(1)初始化一个线程
@Configuration
@EnableAsync
public class ThreadPoolConfig4DAPI {@Bean("apiScheduleThreadPool")
public Executor apiScheduleThreadPool() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(4);
executor.setQueueCapacity(Integer.MAX_VALUE);
executor.setKeepAliveSeconds(60);
executor.setThreadNamePrefix("apiSchedule-");
// 线程池拒绝策略;
/**
* AbortPolicy:丢弃并抛出异常
* DiscardPolicy:丢弃但不抛异常
* DiscardOldestPolicy:丢弃最老的,把新的加进去
* CallerRunsPolicy:主线程运行
*/
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}
(2)@Scheduled指定线程池
/**
* 日志统计: 不加异步可能到点不执行
* @Scheduled定时任务默认使用单线程模式导致的问题;一旦有一个定时任务比较耗时,就会影响到其它定时任务按时执行。
**/
@Async("apiScheduleThreadPool")
@Scheduled(cron = "0 0/5 * * * ?") // 0 14 14 * * ? 5 0 0 * * ?
@RedisLock(value = "Bcrz2DytjTask", leaseTime = 240, waitTime = 240)
public void dailyTask() {
}
4761

被折叠的 条评论
为什么被折叠?



