http://blog.itpub.NET/11627468/viewspace-1766967/

quartz启动后有多个线程同时在跑。启动时会启动主线程、集群线程、检漏线程、工作线程。主线程负责查询到需要触发的线程,并放入到线程队列。
集群线程负责集群、检漏线程负责对未成功执行的任务进行检漏。工作线程默认是20,一般PC服务器可以调到200。


一、主线程QuartzScheduleThread
关于QuartzScheduleThread是quartz启动时开始启动,用于trigger的获取、触发,并放入到线程池中执行。
详细可以看quartz详解2:quartz由浅入深 第4章
quartz详解4:quartz线程管理
详细流程如下:
quartz详解4:quartz线程管理
关于quartz2.0版本之后可以批量执行trigger的功能。要测试是否影响定时的准确度。


二、线程池SimpleThreadPool
线程池的初使化:new 线程并放入线程池的链表中。
执行线程:把任务放到一个线程中执行。
线程结束:修改线程状态。
线程池关闭:每个线程关闭,正在执行的线程等线程执行完了再关闭。
quartz详解4:quartz线程管理


三、工作线程WorkThread
线程池中执行的工作线程,可以通过配置文件quartz.properties来配置大小:
quartz详解4:quartz线程管理
JobRunShell实现runnable接口,放入到workThread下执行:
quartz详解4:quartz线程管理

四、集群线程ClusterManager和检漏线程MisfireHandler
可以看到quartz启动时,这两个线程也启动了。
quartz详解4:quartz线程管理
那么,它是在什么时候启动的呢?是在执行QuartzScheduler的start()方法时在JobStore类上加载的。
quartz详解4:quartz线程管理

再来分析下,这两个线程的作用。
quartz详解4:quartz线程管理
这两个线程都有initialize,manage,run,shutdown方法。
--1、先看ClusterManager,在new ClusterManger后,就会触发initialize方法,initialize方法再调用manager方法。
run方法的代码:

点击(此处)折叠或打开

  • public void run() {
  •             while (!shutdown) {
  •                 if (!shutdown) {
  •                     long timeToSleep = getClusterCheckinInterval();
  •                     long transpiredTime = (System.currentTimeMillis() - lastCheckin);
  •                     timeToSleep = timeToSleep - transpiredTime;
  •                     if (timeToSleep <= 0) {
  •                         timeToSleep = 100L;
  •                     }
  •                     if(numFails > 0) {
  •                         timeToSleep = Math.max(getDbRetryInterval(), timeToSleep);
  •                     }
  •                     
  •                     try {
  •                         Thread.sleep(timeToSleep);
  •                     } catch (Exception ignore) {
  •                     }
  •                 }
  •                 if (!shutdown && this.manage()) {
  •                     signalSchedulingChangeImmediately(0L);
  •                 }
  •             }//while !shutdown
  •         }
  • private long clusterCheckinInterval = 7500L;   //默认7.5秒执行一次集群的manage。
    而集群的manager做的事情是判断是否有节点down掉,同时每7.5秒发送同步心跳修改数据库信息。
    quartz详解4:quartz线程管理
    LAST_CHECKIN_TIME每7.5秒会更新一次。
    quartz详解4:quartz线程管理
    --2、再看MisfireHandler的作用:
    run方法默认每15秒执行一次。如果没有misfire的话,则每60秒执行一次。
    manager逻辑如下:
     private long misfireThreshold = 60000L;   //默认时间超过了1分钟。
    就是把超过1分钟还没执行的任务,认为是misfire,然后保存到trigger表,等待重新再执行。
    quartz详解4:quartz线程管理
    有状态的job如果第一次没有执行完,第二次执行的时间错过了,就会被认为是misfire
    doUpdateOfMisfiredTrigger调用CronTriggerImpl的updateAfterMisfire方法。
    如果misfire设置为MISFIRE_INSTRUCTION_SMART_POLICY或MISFIRE_INSTRUCTION_FIRE_ONCE_NOW就是马上执行。
    如果misfire设置为MISFIRE_INSTRUCTION_DO_NOTHING则在下一个周期再执行。
    默认是:MISFIRE_INSTRUCTION_SMART_POLICY
    可以通过trigger的build方法增加参数实现:
    withMisfireHandlingInstructionFireAndProceed().build()
    withMisfireHandlingInstructionDoNothing().build()

    五、总结:
    从线程角度来分析集群的性能的话,主要是:
    1、主线程QuartzScheduleThread的瓶颈很可能出现在数据库行锁。
    --可以考虑定时任务数据保存在分布式缓存。减少对数据库的过分依赖。
    2、工作线程WorkThread的瓶颈很可能出现在任务的阻塞。
    --可以通过用异步任务来解析,异步任务如何放在数据库有性能问题可以再考虑分布式缓存。

    相关文章:

    • 2022-01-02
    • 2021-12-06
    • 2022-02-06
    • 2021-06-19
    • 2021-07-06
    • 2022-12-23
    • 2021-11-10
    猜你喜欢
    • 2021-05-16
    • 2022-03-02
    • 2021-11-13
    • 2022-12-23
    • 2021-08-16
    • 2021-08-22
    相关资源
    相似解决方案