quartz 主要源码解读

看的是最新版本的源码:(后面两个包,需要单独引用进来,否则报错)

compile group: 'org.quartz-scheduler', name: 'quartz', version: '2.2.2'
compile group: 'commons-collections', name: 'commons-collections', version: '3.2.1'
compile group: 'commons-logging', name: 'commons-logging', version: '1.2'

测试代码如下:

TestJob Job {

    (JobExecutionContext jobCtx)JobExecutionException
    {
        System..println(jobCtx.getTrigger().getClass().getName()++Date())}

    ( String[] args )
    {
        System..println(){
            JobDetail jobdetail = JobBuilder.(TestJob.).withIdentity().build()SimpleTrigger simpleTrigger = TriggerBuilder.()
                    .startAt(Date())
                    .withSchedule(
                            SimpleScheduleBuilder.()
                                    .withIntervalInSeconds()
                                    .repeatForever()
                    )
                    .build()SchedulerFactory schedulerFactory=StdSchedulerFactory()Scheduler scheduler= schedulerFactory.getScheduler()scheduler.scheduleJob(jobdetailsimpleTrigger)scheduler.start()}(Exception ex)
        {
            ex.printStackTrace()}


    }
}

新版的JobDetail和trigger需要使用buidler建造器模式生成,支持链式操作。

有以下主要的类:

public class StdScheduler implements Scheduler
public class JobDetailImpl implements Cloneable, java.io.Serializable, JobDetail
public interface SimpleTrigger extends Trigger  还有很多其他的比如CronTrigger,这个生产中用的最多
public class RAMJobStore implements JobStore 生产上用的是 JobStoreTX,从数据库拿数据

这次主要看以下两个类, 也是2种 主要的线程:

public class QuartzSchedulerThread extends Thread 这个类就是一个线程,有个run方法,负责将任务trigger到
后面的那个SimpleThreadPool,然后SimpleThreadPool将这个job放到WorkThread子类执行。
大致流程为:(这个类的run方法是整个quartz的核心)
1. 检查sigLock和paused 对象,十分需要开始trigger流程。
synchronized (sigLock) {
    while (paused && !halted.get()) {
        try {
            // wait until togglePause(false) is called...
            sigLock.wait(1000L);
        } catch (InterruptedException ignore) {
        }
    }

    if (halted.get()) {
        break;
    }
}
2. 从JobStore里面拿到数量和可用工作线程数量相同的,最近时间的List<OperableTrigger>,trigger里面包含下一次触发的时间
以及要执行的job对象。
triggers = qsRsrcs.getJobStore().acquireNextTriggers(
        now + idleWaitTime, Math.min(availThreadCount, qsRsrcs.getMaxBatchSize()), qsRsrcs.getBatchTimeWindow());
3.检查最近一次的trigger的时间,看看是否需要等待一段时间还是,直接触发:
while(timeUntilTrigger > 2) {
    synchronized (sigLock) {
            try {
                // we could have blocked a long while
                // on 'synchronize', so we must recompute
                now = System.currentTimeMillis();
                timeUntilTrigger = triggerTime - now;
                if(timeUntilTrigger >= 1)
                    sigLock.wait(timeUntilTrigger);
}
4.获取JobRunShell(里面有个JOB对象),并将其送入ThreadPool。
shell = qsRsrcs.getJobRunShellFactory().createJobRunShell(bndle);
qsRsrcs.getThreadPool().runInThread(shell)
public class SimpleThreadPool implements ThreadPool 这个类里面有个子类型:WorkThread就是调用相关Job的
线程,代码就是一个循环,然后在没有任务的时候调用 某个Object对象,阻塞500MS,如果有任务就执行以下
代码如下:
while (run.get()) {
synchronized(lock) {
    while (runnable == null && run.get()) {
        lock.wait(500);
    }

    if (runnable != null) {
        ran = true;
        runnable.run();
    }
}
。。。。runnable = null;。。。。。。此处省略后面处理的代码

还有一个没细看的,就是每次在JobStore里面拿到最近需要触发的trigger,是怎么拿的,每种JobStore,都是各自实现的。看看RAMJobStore的acquireNextTriggers方法:

这个方法默认拿的是,最近3秒内会被触发的Triggers的列表,MaxCount可以配置,是配置数目与可以工作线程数中取最小值。MaxCount 默认为 1.

TimeTrigger是一个TreeSet的数据结构,按照nextFireTime作为Comparator,这样就能拿到最新需要触发的Trigger 列表

while (true) {
    TriggerWrapper tw;

    try {
        tw = timeTriggers.first();
        if (tw == null)
            break;
        timeTriggers.remove(tw);
        OperableTrigger trig = (OperableTrigger) tw.trigger.clone();
        result.add(trig);

        if (result.size() == maxCount)
        break;
}
return result;

末尾贴一篇博客,涉及基于数据库的JobStore的实现。

http://www.cnblogs.com/davidwang456/p/4205237.html

在贴一篇博客,涉及集群部署的配置,数据库为MYSQL。

http://www.cnblogs.com/davidwang456/p/4205237.html

集群部署还是有点麻烦,会有若干张表,获得trigger的时候,QuartzSchedualThread

1. 会对Locks表做一个加锁的操作, 然后,将获取到的trigger记录,从waiting状态更新到accqured状态。

2. 触发之前,会将记录从accqured状态更新到complete状态,并计算nextfire的时间。

3. 触发job。进行下一轮获取。

4. 如果trigger 数量为0, 则会进入run方法最下面那一段,随机休眠一段时间,据网友说,这是集群的默认的负载平衡的策略。

后面是全部的数据库表名:

String TABLE_JOB_DETAILS = String TABLE_TRIGGERS = String TABLE_SIMPLE_TRIGGERS = String TABLE_CRON_TRIGGERS = String TABLE_BLOB_TRIGGERS = String TABLE_FIRED_TRIGGERS = String TABLE_CALENDARS = String TABLE_PAUSED_TRIGGERS = String TABLE_LOCKS = String TABLE_SCHEDULER_STATE =

 

转载于:https://my.oschina.net/u/2504171/blog/530494

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值