ThreadPoolTaskScheduler 注意事项
程序员文章站
2024-03-24 16:10:34
...
在 Spring 中动态管理定时任务,通过简单的一句自动注入 ThreadPoolTaskScheduler 对象的代码,即可轻松实现,参见 Spring动态管理定时任务——ThreadPoolTaskScheduler 。
一、问题抛出
但如果没有查看 ThreadPoolTaskScheduler 的源码,则要特别注意 ThreadPoolTaskScheduler 中,初始化 poolSize=1。源码如下:
@SuppressWarnings("serial")
public class ThreadPoolTaskScheduler extends ExecutorConfigurationSupport
implements AsyncListenableTaskExecutor, SchedulingTaskExecutor, TaskScheduler {
private volatile int poolSize = 1;
....
}
所以将会导致多个任务串行方式执行,而如果前面的某个任务一直没执行结束(比如不限制次数的重试机制),则会使得后面的任务一直没有机会执行。
二、问题复现
复现日志1(正常情况):
【结论一】:可以看到4个(corn=0 0 8 * * ?)的定时任务串行执行。
上面的日志里没打印线程名(log4j中用%t代表),如果打印出来,则将是同一线程。
jconsole查看线程名称:
也可验证 ThreadPoolTaskScheduler 默认 poolSize 只有1,所以上面的4个任务是串行执行。
复现日志2(异常情况):
【结论二】:任务7执行成功,紧接着轮到任务9,而我的业务要求每个任务失败必须一直重试,导致后面的任务没有机会执行。
三、解决方案
即设置 poolSize,如下:
/**
* 数据同步定时任务调度器
*/
@Bean(autowire = Autowire.BY_NAME, name = "sync")
public ThreadPoolTaskScheduler threadPoolTaskScheduler4Sync() {
ThreadPoolTaskScheduler syncScheduler = new ThreadPoolTaskScheduler();
syncScheduler.setPoolSize(5);
syncScheduler.setThreadGroupName("syncTg");
syncScheduler.setThreadNamePrefix("syncThread-");
return syncScheduler;
}
@Resource(name = "sync")
private ThreadPoolTaskScheduler threadPoolTaskScheduler;
验证一下,jconsole查看线程名称和个数:
以上。