原文:https://www.cnblogs.com/youtianhong/p/6027249.html
最近发现个生产问题,定时器任务某些任务没有及时执行。经过研究排查发现spring 定时器任务scheduled-tasks默认配置是单线程串行执行的,这就造成了若某个任务执行时间过长,其他任务一直在排队,业务逻辑没有及时处理的问题。
如下是scheduled定义了3个任务。
<task:scheduled-tasks > <task:scheduled ref="myTask1" method="run" cron="0 0/59 10-23 * * ?"/> <task:scheduled ref="myTask2" method="run" cron="0/10 * * * * ?"/> <task:scheduled ref="myTask3" method="run" cron="0/10 * * * * ?"/> </task:scheduled-tasks>
查看该任务17点的执行日志(task名字已修改)
zgrep -e '2016-10-28 17:' channel-task.log.2016-10-28.log.gz | grep -e 'MyTask2'
2016-10-28 17:14:25,002 INFO [pool-8-thread-1 - ] task.AbstractTask - [TASK] start task >> .MyTask2@186d315
2016-10-28 17:14:35,980 INFO [pool-8-thread-1 - ] task.AbstractTask - [TASK] complete task MyTask2@186d315
2016-10-28 17:14:40,002 INFO [pool-8-thread-1 - ] task.AbstractTask - [TASK] start task >> .MyTask2@186d315
2016-10-28 17:14:50,681 INFO [pool-8-thread-1 - ] task.AbstractTask - [TASK] complete task .MyTask2@186d315
2016-10-28 17:14:55,003 INFO [pool-8-thread-1 - ] task.AbstractTask - [TASK] start task >> .MyTask2@186d315
2016-10-28 17:15:05,613 INFO [pool-8-thread-1 - ] task.AbstractTask - [TASK] complete task MyTask2@186d315
2016-10-28 17:20:35,246 INFO [pool-8-thread-1 - ] task.AbstractTask - [TASK] start task >> .MyTask2@186d315
2016-10-28 17:20:46,051 INFO [pool-8-thread-1 - ] task.AbstractTask - [TASK] complete task .MyTask2@186d315
2016-10-28 17:20:50,003 INFO [pool-8-thread-1 - ] task.AbstractTask - [TASK] start task >> .MyTask2@186d315
2016-10-28 17:21:00,974 INFO [pool-8-thread-1 - ] task.AbstractTask - [TASK] complete task MyTask2@186d315
MyTask2每10秒钟执行一次,但是在17:15:05 到17:20:35之间,5分钟内定时任务没有执行
执行命令 zgrep -e '2016-10-28 17:1' task.log.2016-10-28.log.gz (当天17点10几分发生的日志)
然后在查询日志发现,这5分钟之内有大量的日志在执行
2016-10-28 17:17:20,202 INFO [pool-8-thread-1 - ] task.MyTask3 - compare query order[ 211621610280893418 ]
2016-10-28 17:17:20,477 INFO [pool-8-thread-1 - ] task.MyTask3 - compare query order[ 211621610280893401 ]
2016-10-28 17:17:20,731 INFO [pool-8-thread-1 - ] task.MyTask3 - compare query order[ 211621610280893402 ]
.........中间省略n条日志
2016-10-28 17:19:59,752 INFO [pool-8-thread-1 - ] task.MyTask3 - compare query order[ 211621610280894049 ]
通过过以上日志可以看出,该线程[pool-8-thread-1 - ] 一直在处理MyTask3任务,此时断定 task:scheduled 配置默认是单线程串行的,
网上查找资料发现如下配置可以解决问题
<task:scheduler id="scheduler" pool-size="3" /> <task:scheduled-tasks scheduler="scheduler" > <task:scheduled ref="myTask1" method="run" cron="0 0/59 11-23 * * ?"/> <task:scheduled ref="myTask2" method="run" cron="0/10 * * * * ?"/> <task:scheduled ref="myTask3" method="run" cron="0/10 * * * * ?"/> </task:scheduled-tasks>
如果是注解的方式
@Scheduled(cron = "0 0/1 * * * ?")
那就在applicationContext.xml文件加入<task:scheduler id="scheduler" pool-size="2" />这一行,pool-size表示线程的个数
或者是下面的这一种方式
1.简单单任务定时器的spring配置
<!-- 配置定时任务,用于初始化定时器 --> <bean id="InitJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject"> <ref bean="ReportJobTodo"/> </property> <property name="targetMethod"> <value>initJobTrigger</value> </property> <property name="concurrent" value ="false"/> </bean> <bean id="ReportJobTodo" class="cn.com.gsoft.report.timetask.ReportJobTodo"> </bean> <bean id="InitTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> <property name="jobDetail"> <ref bean="InitJobDetail"/> </property> <property name="cronExpression"> <value>* * * * * ?</value> </property> </bean> <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref local="InitTrigger"/> </list> </property> </bean> <!-- 配置定时任务,用于初始化定时器 --> <bean id="InitJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject"> <ref bean="ReportJobTodo"/> </property> <property name="targetMethod"> <value>initJobTrigger</value> </property> <property name="concurrent" value ="false"/> </bean> <bean id="ReportJobTodo" class="cn.com.gsoft.report.timetask.ReportJobTodo"> </bean> <bean id="InitTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean"> <property name="jobDetail"> <ref bean="InitJobDetail"/> </property> <property name="cronExpression"> <value>* * * * * ?</value> </property> </bean> <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref local="InitTrigger"/> </list> </property> </bean>
说明:(1).InitJobDetail实例声明了需要执行的任务。其中targetObject说明了需要执行的方法所在的实例对象,targetMethod说明了要执行的方法,concurrent用于说明多个任务是否同步执行。
(2).InitTrigger声明了一个触发器。jobDetail属性指明需要执行的任务,cronExpression声明了该任务在什么时候执行,该表达式跟linux下的crontab定时程序中使用的表达式是一样的,具体使用方法可以参考文后的参考资料。
(3).SchedulerFactoryBean中可以定义多个触发器,以实现多任务。