zoukankan      html  css  js  c++  java
  • spring定时器任务多任务串行执行问题排查

    原文: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中可以定义多个触发器,以实现多任务。

  • 相关阅读:
    线程阶段性总结——APM,ThreadPool,Task,TaskScheduler ,CancellationTokenSource
    研究BackgroundWorker后发现:AsyncOperation和SynchronizationContext的差异真的很大!
    线程同步——优势、劣势
    APM异步编程模型的优势
    DataGridView的VirtualMode,在大容量数据加载时特别有用
    【C】——C语言的位运算的优势
    【linux】——Linux tar打包命令
    【C】用文件和链表实现学生信息管理
    【C】——回调函数的好处
    【C】strcpy()需谨慎使用;
  • 原文地址:https://www.cnblogs.com/shihaiming/p/8447132.html
Copyright © 2011-2022 走看看