欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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(正常情况):

ThreadPoolTaskScheduler 注意事项

【结论一】:可以看到4个(corn=0 0 8 * * ?)的定时任务串行执行。

上面的日志里没打印线程名(log4j中用%t代表),如果打印出来,则将是同一线程。

jconsole查看线程名称:

ThreadPoolTaskScheduler 注意事项

 也可验证 ThreadPoolTaskScheduler 默认 poolSize 只有1,所以上面的4个任务是串行执行。

复现日志2(异常情况):

ThreadPoolTaskScheduler 注意事项

 【结论二】:任务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查看线程名称和个数:

ThreadPoolTaskScheduler 注意事项

以上。