一、问题来源

  无锡项目现场有需求需要同步第三方数据,组件通过定时任务来实现,定时任务设置每10分钟执行一次,实际使用当中发现,第三方数据更新后,我们这边迟迟同步不到数据,查看日志发现定时任务并没有按照每10分钟执行一次,而是没有什么规律的在不同时间点执行,时快时慢。

  翻阅代码发现,该组件内定时任务很多,其中一个定时任务也是每10分钟执行一次,而且耗时较长,大约每半个小时才能执行完一次任务。所有的定时任务都是使用的@schedule注解完成的,而@schedule注解默认是单线程的,如果定时任务比较多或者有的定时任务比较耗时,当A任务未执行完,而B任务已经到了需要执行的时间点时,当程序检测到还有任务未执行完时,后面的任务会阻塞等待。这应该就是导致出现上述现象的原因。

二、解决方法

1.增加配置类,是定时任务单线程模式变为多线程;

/**
* @描述 定时任务配置。不配置默认为单线程阻塞式
* @创建人 jxx
* @创建时间 2022/3/23
* @修改人和其它信息
*/
@Configuration
public class ScheduleConfig implements SchedulingConfigurer {

@Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
scheduledTaskRegistrar.setScheduler(Executors.newScheduledThreadPool(5));
}
}

2.application.properties配置文件增加配置项,使单线程模式变为多线程;

spring.task.scheduling.pool.size=10

3.启动类添加@EnableAsync注解,在相应方法上添加@Async注解;

注意:该方法会导致,同一个任务,即使上一次执行还未完成,只要时间到,就会再次执行该任务
@Async异步方法默认使用Spring创建ThreadPooITaskExecutor(参考TaskExecutionAutoCorlfiguration ) 。其中默认核心线程数为 8 ,默认最大队列和默认最大线程数都是Integer.MAX_VALUE。创建新线程的条件是队列填满时,而这样的配置队列永远不会填满,如果有@Async注解标注的方法长期占用线程(比如HTTP 长连接等待获取结果 》,在核心 8 个线程数占用满了之后,新的调用就会进入队列,外部表现为没有执行。

 

结合实际情况我选择了第二种方式。

三、总结

  后续springboot中@schedule定时任务尽量使用多线程模式。