Java
Wei Jieyang Lv4

简介

定时器

java有4种类型的定时器 - 参考

  1. Timer和TimerTask
    • import java.util.Timer
  2. ScheduledExecutorService
    • import java.util.concurrent.ScheduledExecutorService
  3. 三方框架 Quartz
  4. 使用线程等待来实现

Timer

ScheduledExecutorService

Quartz

参见官方说明:Quartz Job Scheduler

Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用。Quartz可以用来创建简单或为运行十个,百个,甚至是好几万个Jobs这样复杂的日程序表。

Jobs可以做成标准的 Java 组件或 EJBs。

特点:

  • 具有强大的调度功能,与Spring容易集成,形成灵活的调度功能。
  • 调度环境的持久化机制:可以保存并恢复调度现场,即使系统因为故障关闭,任务调度现场的数据并不会丢失。
  • 灵活的应用方式:可以灵活的定义触发器调度时间表,并可对触发器与任务进行关联映射(通过Name和Group形式为一个的JobKey)。
  • 分布式与集群能力

三大核心元素:

  • Job:定义要执行的任务
    • 表示一个具体的可执行的调度程序,Job (实现Job接口的具体类)是这个可执行程调度程序所要执行的内容,另外 JobDetail 还包含了这个任务调度的方案和策略。
    • 就是我们自己编写的业务逻辑,交给quartz帮我们执行 。
  • triggers:触发器,任务触发策略
    • 可配置调度参数。
    • 简单的讲就是调度作业,什么时候开始执行,什么时候结束执行。
  • scheduler:调度器,关联job和trigger
    • 调度器,Quartz框架的核心
      • 负责管理Quartz应用运行时环境。
      • 不是靠自己做所有的工作,而是依赖框架内一些非常重要的部件。
      • 一个调度容器中可以注册多个 JobDetail 和 Trigger。当 Trigger 与 JobDetail 组合,就可以被 Scheduler 容器调度了。

Quartz不仅仅是线程和线程池管理。为确保可伸缩性,Quartz采用了基于多线程的架构。启动时,框架初始化一套worker线程,这套线程被调度器用来执行预定的作业。这就是Quartz怎样能并发运行多个作业的原理。Quartz依赖一套松耦合的线程池管理部件来管理线程环境。

四种设计模式:

  1. Builer模式
  2. Factory模式
  3. 组件模式
  4. 链式写法

体系结构

quartz框架至少有三百多个类组成,这里我们重点介绍几个它的核心部分

JobDetail

quartz每次都会直接创建一个JobDetail,同时创建一个Job实例,它不直接接受一个Job的实例,但是它接受一个Job的实现类,通过 new instance() 的反射方式来实例一个Job,在这里Job是一个接口,我们需要自己编写类去实现这个接口。

Job接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//Job接口文件的内容(包 org.quartz.jobjob)
public interface Job {
void execute(JobExecutionContext var1) throws JobExecutionException;
}

//实现Job接口(引入包 org.quartz.job)
public class MyJob implements Job{
public void execute(JobExecutionContext context) throws JobExecutionException {
//编写我们自己的业务逻辑
System.out.println("Hello World! MyJob is executing.");
LocalDateTime nowTime = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
System.out.println("---------" + formatter.format(nowTime));
// 获取Scheduler
Scheduler scheduler = context.getScheduler();
// 获取Trigger
Trigger trigger = context.getTrigger();
// 通过Trigger获取JobDataMap参数
JobDataMap triggerJobData = trigger.getJobDataMap();
// 获取JobDetail
JobDetail jobDetail = context.getJobDetail();
// 通过JobDetail获取JobDetail参数
JobDataMap jobDetailData = jobDetail.getJobDataMap();
// 合并获取JobDataMap,存在键值相同的,取Trigger JobDataMap的值
JobDataMap mergedJobDataMap = context.getMergedJobDataMap();
}
}
  • Job接口,只有一个 execute(JobExecutionContext context) 方法,用于编写具体的任务业务逻辑。
  • 当调度器需要执行 job 时创建实例,调用完成后释放 job 实例。

JobExecutionContext

Job能通过 JobExecutionContext 访问 Quartz 运行环境以及 Job 的明细数据,当 Scheduler 调用 Job 时能将数据传递给 execute() 方法。

JobDataMap

是一个JDK中Map接口实例,在任务调度时存在于 JobExecutionContext 中,可将参数对象传递给在运行的 Job 实例;而且,它自身有方便的方法可存取基本数据类型。

1
2
3
public class JobDataMap extends StringKeyDirtyFlagMap implements Serializable {...}
public class StringKeyDirtyFlagMap extends DirtyFlagMap<String, Object> {...}
public class DirtyFlagMap<K, V> implements Map<K, V>, Cloneable, Serializable {...}

JobBuiler

主要是用来创建jobDeatil实例

JobDetail

1
2
3
4
// 可以通过下面的方式将一个Job实现类绑定到JobDetail中
JobDetail jobDetail = JobBuilder.newJob(MyJob.class)
.withIdentity("myJob", "group1")
.build();
  • 每次都会直接创建一个JobDetail,同时创建一个Job实例,它不直接接受一个Job的实例,但是它接受一个Job的实现类,通过new instance()的反射方式来实例一个Job
  • 描述 Job 实列的详细信息。
    • name:job名称;
    • group:job组。默认值为default;
    • jobClass:job接口实现类的class;
    • jobDataMap:存储Job实例的状态信息,调度器使用这些信息添加 Job 实例。

JobStore

绑定了Job的各种数据

1

Trigger

它由SimpleTrigger和CronTrigger组成,SimpleTrigger实现类似Timer的定时调度任务,CronTrigger可以通过cron表达式实现更复杂的调度逻辑·。

Scheduler

调度器,JobDetail和Trigger可以通过Scheduler绑定到一起。

SchedulerBuilder

设置任务执行计划,如多久执行一次,是否重复执行,延迟多久执行等。

具体对象和常用方法

  1. CronScheduleBuilder(常用):它为触发器定义了基于 cronexpress 的调度。该对象的主要通过 Cron 表达式来进行创建,底层代码基本都是将对应参数转换为 Cron表达式后进行创建。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//通过指定 Cron 表达式创建对象
ScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("0/5 * * * * ?");

//源码
public class CronScheduleBuilder extends ScheduleBuilder<CronTrigger> {
private CronExpression cronExpression;
private int misfireInstruction = 0;

protected CronScheduleBuilder(CronExpression cronExpression) {
if (cronExpression == null) {
throw new NullPointerException("cronExpression cannot be null");
} else {
this.cronExpression = cronExpression;
}
}

public static CronScheduleBuilder cronSchedule(String cronExpression) {
try {
return cronSchedule(new CronExpression(cronExpression));
} catch (ParseException var2) {
throw new RuntimeException("CronExpression '" + cronExpression + "' is invalid.", var2);
}
}
}
  1. SimpleScheduleBuilder:它为触发器定义了基于严格/文字间隔的调度。能指定触发的间隔时间和执行次数;

    • build():构建实际的触发器
    • simpleSchedule():static 方法,获取一个 SimpleScheduleBuilder 对象
      repeatForever():指定触发器将无限重复。
    • withRepeatCount(int triggerRepeatCount):设置重复执行次数
    • repeatlyForever():设置对应时间单位执行一次,无限重复
    • repeatlyForever(int):设置当前对应时间单位 * int 执行一次,无限重复
    • withIntervalIns(int/long):根据对应时间单位设置执行间隔
  2. CalendarIntervalScheduleBuilder:它为触发器定义基于间隔的日历时间(天、周、月、年)调度。

    • build():构建实际的触发器
    • calendarIntervalSchedule():创建一个 CalendarIntervalScheduleBuilder。
    • preserveHourOfDayAcrossDaylightSavings(boolean preserveHourOfDay):如果间隔是一天或更长的时间,这个属性(设置为 true )将导致触发器的触发总是在一天的同一时间发生,( startTime 的时间),而不考虑夏令时转换。
    • withInterval(int timeInterval, DateBuilder.IntervalUnit unit):指定要生成的触发器的时间单位和间隔。
    • withIntervalIn___s(int intervalInDays):在 IntervalUnit 中指定一个 interval。所产生的触发器将重复对应时间单位。
  3. DailyTimeIntervalScheduleBuilder:此生成器为您提供了一个额外的方便方法来设置触发器的 endTimeOfDay。

    • build():构建实际的触发器
    • dailyTimeIntervalSchedule():创建一个 DailyTimeIntervalScheduleBuilder。
    • endingDailyAfterCount(int count):使用 count、interval 和 starTimeOfDay 计算和设置 endTimeOfDay。
    • endingDailyAt(TimeOfDay timeOfDay):设置此触发器的每日开始时间,以在给定的时间结束每天的触发。
    • onDaysOfTheWeek(onDaysOfWeek):将触发器设置为在一周中的特定日期触发。
    • onEveryDay():触发时间为一周中的任何一天。
    • onMondayThroughFriday():把周一到周五的日子设为触发时间。
    • onSaturdayAndSunday():触发时间为星期六和星期天。
    • startingDailyAt(TimeOfDay timeOfDay):设置触发开始每天在给定的时间。
    • withInterval(int timeInterval, DateBuilder.IntervalUnit unit):指定要生成的触发器的时间单位和间隔。
    • withIntervalIns(int):在 IntervalUnit 中指定一个 interval。所产生的触发器将重复的时间。
    • withRepeatCount(int repeatCount):设置间隔重复的次数。
  4. ScheduleBuilder:设置任务执行计划,如多久执行一次,是否重复执行,延迟多久执行等。

  5. Scheduler:调度器,管理任务调取容器。

使用

job

triggers

触发器:简单的讲就是调度作业,什么时候开始执行,什么时候结束执行。

scheduler

调度器 :Quartz框架的核心是调度器。

  • 调度器负责管理Quartz应用运行时环境。
  • 调度器不是靠自己做所有的工作,而是依赖框架内一些非常重要的部件。
  • Quartz不仅仅是线程和线程池管理。为确保可伸缩性,Quartz采用了基于多线程的架构。启动时,框架初始化一套worker线程,这套线程被调度器用来执行预定的作业。这就是Quartz怎样能并发运行多个作业的原理。Quartz依赖一套松耦合的线程池管理部件来管理线程环境。
1
2
3
4
5
6
// 工厂方式创建调度器实例Scheduler
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
...
scheduler.scheduleJob(job, trigger); //将任务与触发器关联起来
// 启动,开始调度
scheduler.start();
  • Post title:Java
  • Post author:Wei Jieyang
  • Create time:2021-07-08 14:55:40
  • Post link:https://jieyang-wei.github.io/2021/07/08/Java/
  • Copyright Notice:All articles in this blog are licensed under BY-NC-SA unless stating additionally.