• quartz详解4:quartz线程管理


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

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


    一、主线程QuartzScheduleThread
    关于QuartzScheduleThread是quartz启动时开始启动,用于trigger的获取、触发,并放入到线程池中执行。
    详细可以看quartz详解2:quartz由浅入深 第4章

    详细流程如下:

    关于quartz2.0版本之后可以批量执行trigger的功能。要测试是否影响定时的准确度。


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



    三、工作线程WorkThread
    线程池中执行的工作线程,可以通过配置文件quartz.properties来配置大小:

    JobRunShell实现runnable接口,放入到workThread下执行:


    四、集群线程ClusterManager和检漏线程MisfireHandler
    可以看到quartz启动时,这两个线程也启动了。

    那么,它是在什么时候启动的呢?是在执行QuartzScheduler的start()方法时在JobStore类上加载的。


    再来分析下,这两个线程的作用。

    这两个线程都有initialize,manage,run,shutdown方法。
    --1、先看ClusterManager,在new ClusterManger后,就会触发initialize方法,initialize方法再调用manager方法。
    run方法的代码:

    点击(此处)折叠或打开

    1. public void run() {
    2.             while (!shutdown) {
    3.                 if (!shutdown) {
    4.                     long timeToSleep = getClusterCheckinInterval();
    5.                     long transpiredTime = (System.currentTimeMillis() - lastCheckin);
    6.                     timeToSleep = timeToSleep - transpiredTime;
    7.                     if (timeToSleep <= 0) {
    8.                         timeToSleep = 100L;
    9.                     }
    10.                     if(numFails > 0) {
    11.                         timeToSleep = Math.max(getDbRetryInterval(), timeToSleep);
    12.                     }
    13.                     
    14.                     try {
    15.                         Thread.sleep(timeToSleep);
    16.                     } catch (Exception ignore) {
    17.                     }
    18.                 }
    19.                 if (!shutdown && this.manage()) {
    20.                     signalSchedulingChangeImmediately(0L);
    21.                 }
    22.             }//while !shutdown
    23.         }

    private long clusterCheckinInterval = 7500L;   //默认7.5秒执行一次集群的manage。
    而集群的manager做的事情是判断是否有节点down掉,同时每7.5秒发送同步心跳修改数据库信息。

    LAST_CHECKIN_TIME每7.5秒会更新一次。

    --2、再看MisfireHandler的作用:
    run方法默认每15秒执行一次。如果没有misfire的话,则每60秒执行一次。
    manager逻辑如下:
     private long misfireThreshold = 60000L;   //默认时间超过了1分钟。
    就是把超过1分钟还没执行的任务,认为是misfire,然后保存到trigger表,等待重新再执行。

    有状态的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的瓶颈很可能出现在任务的阻塞。
    --可以通过用异步任务来解析,异步任务如何放在数据库有性能问题可以再考虑分布式缓存。

  • 相关阅读:
    [RxJS] sample
    [Whole Web] SQL INJECTION
    [RxJS] Using iif
    [React] Animate SVG Paths with Framer Motion
    bash 教程5 shell 流程控制 条件判断 重定向 read [MD]
    bash 教程4 shell 脚本 调试 环境 [MD]
    『前端算法』数组合并两个有序数组
    块设备读写测试
    IO栈整体认知
    MySQL [Warning] Can’t create test file xxx lowertest(转)
  • 原文地址:https://www.cnblogs.com/SimplifyIT/p/6588374.html
Copyright © 2020-2023  润新知