quartz原理

Quartz是一个开源的作业调度框架,它通过Scheduler、JobDetail和Trigger实现任务调度。任务执行依赖线程池,包含调度线程和执行线程。配置文件主要涉及调度器实例名、数据存储方式、线程池设置等。Quartz支持CronTrigger和SimpleTrigger,并使用JDBC存储任务信息,通过数据库锁保证任务同步。
摘要由CSDN通过智能技术生成

1.如何实现任务

2.3个组件

3.工作原理

在Quartz中,有两类线程,Scheduler调度线程和任务执行线程,其中任务执行线程通常使用一个线程池维护一组线程。

Scheduler调度线程主要有两个:执行常规调度的线程,和执行misfiredtrigger的线程。常规调度线程轮询存储的所有trigger,如果有需要触发的trigger,即到达了下一次触发的时间,则从任务执行线程池获取一个空闲线程,执行与该trigger关联的任务。Misfire线程是扫描所有的trigger,查看是否有misfiredtrigger,如果有的话根据misfire的策略分别处理(fire now OR wait for the next fire)

当一个任务执行完,通过这2个时间来控制下一个定时周期

4.调度

  1. JobDetail 表示一个具体的可执行的调度程序,Job 是这个可执行程调度程序所要执行的内容,另外 JobDetail 还包含了这个任务调度的方案和策略。
  2. Trigger 触发器,指定何时触发任务。
  3. Scheduler 代表一个调度容器,一个调度容器中可以注册多个 JobDetail 和 Trigger。当 Trigger 与 JobDetail 组合,就可以被 Scheduler 容器调度了。

参考配置文档

Quartz配置参考_w3cschool

调度器:

  Quartz 框架的核心是调度器。调度器负责管理 quartz 应用运行时环境。调度器不是靠自己做所有工作,而是依赖框架内一些非常重要的部件。quartz 不仅仅是线程和线程管理。为确保可伸缩性,quartz 采用了基于多线程的架构。启动时,架构初始化一套 worker 线程,这套线程被调度器用来执行预定的作业。这就是 quartz 怎样能并发运行多个作业的原理。quartz 依赖一套松耦合的线程池管理部件来管理线程环境

表名称    说明
qrtz_blob_triggers    Trigger作为Blob类型存储(用于Quartz用户用JDBC创建他们自己定制的Trigger类型,JobStore 并不知道如何存储实例的时候)
qrtz_calendars    以Blob类型存储Quartz的Calendar日历信息, quartz可配置一个日历来指定一个时间范围
qrtz_cron_triggers    存储Cron Trigger,包括Cron表达式和时区信息。
qrtz_fired_triggers    存储与已触发的Trigger相关的状态信息,以及相联Job的执行信息
qrtz_job_details    存储每一个已配置的Job的详细信息
qrtz_locks    存储程序的非观锁的信息(假如使用了悲观锁)

可以看出采用了Quartz集群采用了悲观锁的方式对triggers表进行行加锁, 以保证任务同步的正确性。当线程使用上述的SQL对表中的数据执行操作时,数据库对该行进行行加锁; 于此同时, 另一个线程对该行数据执行操作前需要获取锁, 而此时已被占用, 那么这个线程就只能等待, 直到该行锁被释放

qrtz_paused_trigger_graps    存储已暂停的Trigger组的信息
qrtz_scheduler_state    存储少量的有关 Scheduler的状态信息,和别的 Scheduler 实例(假如是用于一个集群中)
qrtz_simple_triggers    存储简单的 Trigger,包括重复次数,间隔,以及已触的次数
qrtz_triggers    存储已配置的 Trigger的信息
qrzt_simprop_triggers    

6. 配置文件 
quartz.properties 
//调度标识名 集群中每一个实例都必须使用相同的名称 (区分特定的调度器实例) 
org.quartz.scheduler.instanceName:DefaultQuartzScheduler 
//ID设置为自动获取 每一个必须不同 (所有调度器实例中是唯一的) 
org.quartz.scheduler.instanceId :AUTO 
//数据保存方式为持久化 
org.quartz.jobStore.class :org.quartz.impl.jdbcjobstore.JobStoreTX 
//表的前缀 
org.quartz.jobStore.tablePrefix : QRTZ_ 
//设置为TRUE不会出现序列化非字符串类到 BLOB 时产生的类版本问题 
//org.quartz.jobStore.useProperties : true 
//加入集群 true 为集群 false不是集群 
org.quartz.jobStore.isClustered : false 
//调度实例失效的检查时间间隔 
org.quartz.jobStore.clusterCheckinInterval:20000 
//容许的最大作业延长时间 
org.quartz.jobStore.misfireThreshold :60000 
//ThreadPool 实现的类名 
org.quartz.threadPool.class:org.quartz.simpl.SimpleThreadPool 
//线程数量 
org.quartz.threadPool.threadCount : 10 
//线程优先级 
org.quartz.threadPool.threadPriority : 5(threadPriority 属性的最大值是常量 java.lang.Thread.MAX_PRIORITY,等于10。最小值为常量 java.lang.Thread.MIN_PRIORITY,为1) 

线程池的工作原理

1.线程在有任务的时候会创建核心的线程数corePoolSize

2.当线程满了(有任务但是线程被使用完)不会立即扩容,而是放到阻塞队列中,当阻塞队列满了之后才会继续创建线程。

3.如果队列满了,线程数达到最大线程数则会执行拒绝策略


//自创建父线程 
//org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true 
//数据库别名 
org.quartz.jobStore.dataSource : qzDS 
//设置数据源 
org.quartz.dataSource.qzDS.driver:com.mysql.jdbc.Driver 
org.quartz.dataSource.qzDS.URL:jdbc:mysql://localhost:3306/quartz 
org.quartz.dataSource.qzDS.user:root 
org.quartz.dataSource.qzDS.password:123456 
org.quartz.dataSource.qzDS.maxConnection:10

7.JDBC插入表顺序

主要的JDBC操作类,执行sql顺序。 
Simple_trigger :插入顺序 
qrtz_job_details —> qrtz_triggers —> qrtz_simple_triggers 
qrtz_fired_triggers 
Cron_Trigger:插入顺序 
qrtz_job_details —> qrtz_triggers —> qrtz_cron_triggers 
qrtz_fired_triggers

简单的测试启动示例应用程序

下载和安装完 quartz 后,是时候开发一个示例应用,并让它跑起来了。下面的示例代码,获取 scheduler 实例对象,启动,然后关闭。

QuartzTest.java

import org.quartz.Scheduler;
  import org.quartz.SchedulerException;
  import org.quartz.impl.StdSchedulerFactory;
  import static org.quartz.JobBuilder.*;
  import static org.quartz.TriggerBuilder.*;
  import static org.quartz.SimpleScheduleBuilder.*;

  public class QuartzTest {

      public static void main(String[] args) {

          try {
              // Grab the Scheduler instance from the Factory
              Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

              // and start it off
              scheduler.start();

              scheduler.shutdown();

          } catch (SchedulerException se) {
              se.printStackTrace();
          }
      }
  }
  • 当你调用 StdSchedulerFactory.getDefaultScheduler () 获取 scheduler 实例对象后,在调用 scheduler.shutdown () 之前,scheduler 不会终止,因为还有活跃的线程在执行。。

注意示例代码中的静态导入 (static import),下面的代码中也会用到它们。

如果你没有配置日志输出,所有的日志会输出到控制台,比如:

[INFO] 21 Jan 08:46:27.857 AM main [org.quartz.core.QuartzScheduler]
Quartz Scheduler v.2.0.0-SNAPSHOT created.

[INFO] 21 Jan 08:46:27.859 AM main [org.quartz.simpl.RAMJobStore]
RAMJobStore initialized.

[INFO] 21 Jan 08:46:27.865 AM main [org.quartz.core.QuartzScheduler]
Scheduler meta-data: Quartz Scheduler (v2.0.0) 'Scheduler' with instanceId 'NON_CLUSTERED'
  Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally.
  NOT STARTED.
  Currently in standby mode.
  Number of jobs executed: 0
  Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 50 threads.
  Using job-store 'org.quartz.simpl.RAMJobStore' - which does not support persistence. and is not clustered.


[INFO] 21 Jan 08:46:27.865 AM main [org.quartz.impl.StdSchedulerFactory]
Quartz scheduler 'Scheduler' initialized from default resource file in Quartz package: 'quartz.properties'

[INFO] 21 Jan 08:46:27.866 AM main [org.quartz.impl.StdSchedulerFactory]
Quartz scheduler version: 2.0.0

[INFO] 21 Jan 08:46:27.866 AM main [org.quartz.core.QuartzScheduler]
Scheduler Scheduler_$_NON_CLUSTERED started.

[INFO] 21 Jan 08:46:27.866 AM main [org.quartz.core.QuartzScheduler]
Scheduler Scheduler_$_NON_CLUSTERED shutting down.

[INFO] 21 Jan 08:46:27.866 AM main [org.quartz.core.QuartzScheduler]
Scheduler Scheduler_$_NON_CLUSTERED paused.

[INFO] 21 Jan 08:46:27.867 AM main [org.quartz.core.QuartzScheduler]
Scheduler Scheduler_$_NON_CLUSTERED shutdown complete.

你可以在 start () 和 shutdown () 之间做一些有趣的事情:

  // define the job and tie it to our HelloJob class
  JobDetail job = newJob(HelloJob.class)
      .withIdentity("job1", "group1")
      .build();

  // Trigger the job to run now, and then repeat every 40 seconds
  Trigger trigger = newTrigger()
      .withIdentity("trigger1", "group1")
      .startNow()
            .withSchedule(simpleSchedule()
              .withIntervalInSeconds(40)
              .repeatForever())            
      .build();

  // Tell quartz to schedule the job using our trigger
  scheduler.scheduleJob(job, trigger);
在调用 shutdown () 之前,你需要给 job 的触发和执行预留一些时间,比如,你可以调用 Thread.sleep (60000) 让线程睡眠一段时间。
好文备份
Quartz SimpleThreadPool的源码,一个简单的线程池的实现原理_汪小哥的博客-CSDN博客
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值