Quartz入门(一)

て烟熏妆下的殇ゞ 提交于 2020-02-14 01:58:47

Quartz核心概念

  • Scheduler调度器,一个调度器中可以注册多个JobDetail和Trigger,当Trigger与JobDetail组合,就可以被Scheduler容器调度了。
  • Trigger 触发器,表示一个调度参数的配置,什么时候去执行
  • JobDetail 表示一个具体可以执行的调度程序,Job 是这个可执行程调度程序所要执行的内容,另外 JobDetail 还包含了这个任务调度的方案和策略。
  • Job 表示一个工作,要执行的具体内容。此接口中只有一个方法,如下:
public void execute(JobExecutionContext context) 

1 调度器Scheduler

  • Scheduler:调度器。就是quartz的大脑,所有任务都是由它来实施。包含两个重要的组件JobStoreThreadPool
    JobStore 是存储运行时信息的,包括Trigger,Scheduler,JobDetail,业务锁等
    ThreadPool就是线程池,Quartz有自己的线程池实现。所有任务都会由线程池执行。
  • SchedulerFactory: Scheduler工厂,有两个实现类DirectSchedulerFactoryStdSchedulerFactory。前者可以用来在代码里定制你自己的scheduler参数。后者是直接读取配置文件(如果没有配置,则采取默认的)来实例化Scheduler。SchedulerFactory本身是支持创建RMI stub的,可以用来管理远程的Scheduler,功能与本地一样。

2 触发器Trigger

2.1 SimpleTrigger

  • 指定从某一个时间开始,以一定的时间间隔(单位是毫秒)执行的任务。
  • 适合的任务类似于—【8:00开始,每隔1小时,执行1次】
  • 属性包括repeatInterval(重复间隔);repeatCount (重复次数,实际执行次数是repeatCount+1,因为在startTime的时候一定会执行一次)
  • 示例
SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(1)//每隔一秒执行一次
					.repeatForever() //一直执行
					.build();
SimpleScheduleBuilder.simpleSchedule().withIntervalInMinutes(3)//每隔3分钟执行一次
					.withRepeatCount(3) //执行3次
					.build()

2.2 CalendarIntervalTrigger

指定从某一个时间开始,以一定的时间间隔执行的任务,类似于SimpleTrigger。二者的区别是:
SimpleTrigger指定的时间间隔为毫秒,没办法指定每隔一个月执行一次(每个月的时间间隔不是固定值);CalendarIntervalTrigger支持的间隔单位有秒,分钟,小时,天,月,年,星期。

CalendarIntervalScheduleBuilder.calendarIntervalSchedule().withIntervalInDays(2).build();

2.3 DailyTimeIntervalTrigger

  • 指定每天的某个时间段内,以一定的时间间隔执行任务。并且可以指定星期
  • 适合任务-【每天8:00 -15:00,每隔2分钟执行一次,并且只要求周六执行】
  • 属性有:startTimeOfDay 每天开始时间;endTimeOfDay 每天结束时间;daysOfWeek 需要星期几执行;interval时间间隔;intervalUnit 执行间隔的单位(秒,分钟,小时,天,月,年,星期);repeatCount 重复次数。
  • 示例
	DailyTimeIntervalScheduleBuilder.dailyTimeIntervalSchedule()
		.startingDailyAt(TimeOfDay.hourAndMinuteOfDay(8, 0))//每天8点开始
		.endingDailyAt(TimeOfDay.hourAndMinuteOfDay(15, 0))//每天15点结束
		.onDaysOfTheWeek(Calendar.SATURDAY)//星期六执行
		.withIntervalInHours(1)//每一个小时执行1次
		.withRepeatCount(100)//执行100次
		.build();

2.4 CronTrigger(常用)

  • 适合更复杂的任务,基本上覆盖了以上三个Trigger的绝大部分功能。
  • 适合任务-【每天0点,6点各执行一次】
  • 属性-【cron表达式】
  • 示例:
CronScheduleBuilder.cronSchedule("0 0/2 10-12 * * ?").build();//每天10点-12点 每隔2分钟执行一次

2.4.1 cron表达式

位置 时间域 允许值 特殊值
1 0-59 ,-*/
2 分钟 0-59 ,-*/
3 小时 0-23 ,-*/
4 日期 1-31 ,-*/?LW
5 月份 1-12 ,-*/
6 星期 1-7 ,-*/?L#
7 年份(可选) 1970~2099 ,-*/
  1. 星号(*) :所有字段均可用,表示对应时间域的每一个时刻。在秒字段,就表示“每秒”
  2. 问号(?) :只在日期和星期两个字段中使用,表示“不确定值”。例如想在每月的1日触发调度,不管1日到底是星期几,则只能使用如下写法: 13 13 15 1 * ?, 其中最后一位只能用?,而不能使用*
  3. 减号(-):表示范围。例如在分钟字段使用5-20,表示从5分到20分
  4. 逗号(,):表示列出枚举值。例如在日期字段使用“1,3,5”,则表示每月1日,3日,5日
  5. 斜线(/):表示起始时间开始触发,然后每隔固定时间触发一次。例如在分钟字段使用5/20,则意味着5分钟触发一次,而25,45等分别触发一次. 也可以使用*/y,等同于0/y。
  6. L:表示最后,只能出现在日期和星期字段。L如果在日期字段中,表示这个月份的最后一天,如1月的31日,非闰年的2月的28日。如果用在星期中,则表示星期六,但是如果在星期字段使用5L,意味着在最后的一个星期四触发。
  7. W:只能出现在日期字段,表示有效工作日(周一到周五),系统将在离指定日期的最近的有效工作日触发事件。例如:在 日期字段使用12W,如果12日是星期六,则将在最近的工作日:星期五,即11日触发。如果12日是星期天,则在13日(周一)触发;如果12日在星期一到星期五中的一天,则就在12日触发。另外一点,W的最近寻找不会跨过月份 。比如,指定1W,如果1日是星期六,则在3日出发,而不是上个月的最后那天。W只能指定单一日期,不能指定日期范围
  8. LW:这两个字符可以连用,表示在某个月最后一个工作日,即最后一个星期五。
  9. #:用于确定每个月第几个星期几,只能出现在日期字段。例如在4#2,表示某月的第二个星期三。
    一个在线校验cron表达式的网址

3 Job并发

Job是有肯能并发执行的,比如一任务要执行10秒中才能结束,而调度算法是每秒中触发一次,那么就有可能过个任务被并发执行。
但是有时候我们并不想任务并发执行,比如有个任务要去“获得数据库中多有未发送邮件的名单”,如果是并发执行,就需要一个数据库锁去避免一个数据被多次处理。注解DisallowConcurrentExecution就可以解决这个问题。该注解对JobDetail实例生效,如果你定义两个JobDetail,引用同一个Job类,是可以并发执行的。

@DisallowConcurrentExecution
public class MyJob implements Job{

	@Override
	public void execute(JobExecutionContext context) throws JobExecutionException {
		try {
			Thread.sleep(4000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//创建任务详情
		JobDetail jobDetail = context.getJobDetail();
		String name = jobDetail.getKey().getName();//任务名
		String group = jobDetail.getKey().getGroup();//任务group
		String jobData = jobDetail.getJobDataMap().getString("data");//任务中的数据
		System.out.println("job's name: "+ name + " group: " + group + " data: " + jobData + " " + new Date());
	}

}
@Test
	public void testCronTrigger() {
		try {
			//1. 创建调度器
			Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
			
			//2. 定义一个Trigger,触发条件类
			Trigger trigger = TriggerBuilder.newTrigger()
					.withIdentity("trigger1", "group1")//定义name/group
			.withSchedule(CronScheduleBuilder.cronSchedule("*/2 * * * * ?"))
			.build();
			
			//3. 定义一个JobDetail
			//定义Job类为Myjob类,这是真正的执行逻辑
			JobDetail job = JobBuilder.newJob(MyJob.class).withIdentity("test1","test")//name and group
					.usingJobData("data","Hello")//定义属性,存储数据
					.build();
			
			//4. 调度器中加入任务和触发器
			scheduler.scheduleJob(job, trigger);
			
			//5. 启动调度器
			scheduler.start();
			Thread.sleep(600000);
			scheduler.shutdown();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!