勿以恶小而为之,勿以善小而不为--------------------------刘备

劝诸君,多行善事积福报,莫作恶

上一章简单介绍了 Quartz传递数据和有无状态Job(三),如果没有看过,请观看上一章

一. SimpleScheduleBuilder

SimpleScheduleBuilder,简单调度建造者,用于生成调度时间, 接下来,老蝴蝶重点讲解一下,它的用法。

关于它的接口方法,可以观看第二章节的内容。

一.一 调度方法演示

一.一.一 编写 Job 任务

//用于测试  SimpleScheduleBuilder
public class MyJob8 implements Job {@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {//要做的事,是打印当前的时间 SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//格式化时间String dateString=sdf.format(new Date());System.out.println("备份数据库的时间是:"+dateString);}
}

一.一.二 立即启动,调度方法演示

一.一.二.一 repeatSecondlyForever() 方法

// SimpleScheduleBuilder 方法展示
public class SchedulerDemo8 {public static void main(String[] args) throws  Exception{//获取SchedulerScheduler scheduler= StdSchedulerFactory.getDefaultScheduler();// 创建 JobDetailJobDetail jobDetail=JobBuilder.newJob(MyJob8.class).withIdentity("job1","group1").build();//创建 TriggerTrigger trigger= TriggerBuilder.newTrigger().withIdentity("trigger1","group1") //设置标识.startNow()//每秒钟执行一次.withSchedule(SimpleScheduleBuilder.repeatSecondlyForever()).build();//关联 job和 triggerscheduler.scheduleJob(jobDetail,trigger);//启动 schedulerscheduler.start();}
}

运行程序,控制台打印输出:

一直运行,每1s(默认值) 执行一次

一.一.二.二 repeatSecondlyForever(int seconds) 方法

只需要将调度的那行代码替换可:

 //.withSchedule(SimpleScheduleBuilder.repeatSecondlyForever()).withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(2))

控制台打印输出:

一直运行,每隔两秒(参数传入值)运行一次。

一.一.二.三 repeatSecondlyForTotalCount(int count) 方法

//.withSchedule(SimpleScheduleBuilder.repeatSecondlyForever())
//.withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(2))
.withSchedule(SimpleScheduleBuilder.repeatSecondlyForTotalCount(3))

控制台打印输出:

只运行了三次,每隔1s(默认值)运行。

一.一.二.四 repeatSecondlyForTotalCount(int count, int seconds) 方法

//.withSchedule(SimpleScheduleBuilder.repeatSecondlyForever())
//.withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(2))
//.withSchedule(SimpleScheduleBuilder.repeatSecondlyForTotalCount(3))
.withSchedule(SimpleScheduleBuilder.repeatSecondlyForTotalCount(3, 2))

控制台打印输出:

只运行三次,每隔2s运行。

一.一.三 设置开始日期和结束日期启动

上面启动Trigger时,用的是 startNow(), 立即启动,也可以用 startAt(date) 和endAt(date) 来动态地设置 启动时间和结束时间, 常常用于条件触发和条件结束。

可以在任务里面,通过 JobExecutionContext 上下文来获取 开始时间和结束时间。

一.一.三.一 任务接口

//获取开始时间和结束时间
public class MyJob9 implements Job {@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//格式化时间String dateString=sdf.format(new Date());//是设置的开始时间和结束时间,不会改变System.out.println("开始时间:"+sdf.format(jobExecutionContext.getTrigger().getStartTime()));System.out.println("结束时间:"+sdf.format(jobExecutionContext.getTrigger().getEndTime()));System.out.println("备份数据库的时间是:"+dateString);}
}

一.一.三.二 主程序调用

//startAt 和endAt 的用法
public class SchedulerDemo9 {public static void main(String[] args) throws  Exception{//获取SchedulerScheduler scheduler= StdSchedulerFactory.getDefaultScheduler();// 创建 JobDetailJobDetail jobDetail=JobBuilder.newJob(MyJob9.class).withIdentity("job1","group1").build();//当前时间Date nowDate=new Date();//开始时间为 当前时间往后4s,即推迟4s执行Date startDate=new Date(nowDate.getTime()+4000);//结束时间,往后跑10秒Date endDate=new Date(startDate.getTime()+10000);//创建 TriggerTrigger trigger= TriggerBuilder.newTrigger().withIdentity("trigger1","group1") //设置标识.startAt(startDate).endAt(endDate)// 设置为简单触发器,2s触发一次.withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(2)) .build();//关联 job和 triggerscheduler.scheduleJob(jobDetail,trigger);//启动 schedulerscheduler.start();}
}

一.一.三.三 控制台打印输出

程序运行,大约4s之后,才打印出日志信息:

控制台打印输出:

虽然程序还在运行,但并不会执行任务,结束时间到了,一共执行了5次。

延迟4s执行, endDate-startDate=10s, 每2秒执行一次, 故执行 10/2=5 次。

在结束日期到时,会停止执行任务。

一.一.三.四 注意点

在任务类 MyJob9里面,打印了开始日期和结束日期, 如果在主程序里面,并没有设置 endAt(), 即没有设置结束日期, 那么获取时会出错。

 //.endAt(endDate)

一.一.三.五 结束日期和运行次数先后关系

一.一.三.二的程序时,调度器是一直运行,但触发器Trigger 设置了结束日期, 当时间到达触发器的结束日期时,不会再继续执行作业调度了。

演示1: 当设置调度的次数时(5,5):

  //.withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(2)) // 设置为简单触发器.withSchedule(SimpleScheduleBuilder.repeatSecondlyForTotalCount(5,5)) //想执行5次,超过结束日期

控制台打印输出:

只执行了2次, 到 Trigger 结束时间时暂停。

演示2: 当设置调度次数为(2,2)

//.withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(2)) // 设置为简单触发器
//.withSchedule(SimpleScheduleBuilder.repeatSecondlyForTotalCount(5,5))  //想执行5次,超过结束日期
.withSchedule(SimpleScheduleBuilder.repeatSecondlyForTotalCount(2,2)) //想执行2次,未到结束时间

控制台打印输出:

只执行了2次。

结束日期和调度次数, 哪个条件先触发,就按照哪个条件的结果走。

二. Scheduler 的开启,关闭和挂起

开启是 start(), 与以前一样, 重点是讲解一下 Scheduler 关闭和挂起。

二.一 关闭 shutdown() 及shutdown(flag)

二.一.一 工作任务类

//shutdown 用法
public class MyJob10 implements Job {@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {//要做的事,是打印当前的时间 SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//格式化时间String dateString=sdf.format(new Date());System.out.println("备份数据库的时间是:"+dateString);}
}

二.一.二 主程序测试

二.一.二.一 直接关闭

//shutdown 关闭
public class SchedulerDemo10 {public static void main(String[] args) throws  Exception{//获取SchedulerScheduler scheduler= StdSchedulerFactory.getDefaultScheduler();// 创建 JobDetailJobDetail jobDetail=JobBuilder.newJob(MyJob10.class).withIdentity("job1","group1").build();//创建 TriggerTrigger trigger= TriggerBuilder.newTrigger().withIdentity("trigger1","group1") //设置标识.startNow().withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(2)) // 设置为简单触发器.build();//关联 job和 triggerscheduler.scheduleJob(jobDetail,trigger);//启动 schedulerscheduler.start();//直接关闭scheduler.shutdown();}
}

运行程序,此时控制台打印输出:

直接关闭,没有任何任务执行。

二.一.二.二 休眠后关闭

改变代码,在关闭之前添加上休眠的代码

  //休眠10s后,关闭Thread.sleep(10000);scheduler.shutdown();

运行程序,控制台打印输出:

共执行任务6次,(最开始时 1次+休眠时5次=6次),10s之后,关闭了调度器。

二.一.二.三 关闭后重新开启

关闭之后,是否能重新开启呢?

改变代码, 在 二.一.二.二 的基础上再添加一个 ‘重新启动’ 的代码

//休眠10s后,关闭Thread.sleep(10000);scheduler.shutdown();//休眠2s之后,重新启动Thread.sleep(2000);scheduler.start();

运行程序,控制台打印输出:

Exception in thread “main” org.quartz.SchedulerException: The Scheduler cannot be restarted after shutdown() has been called.

同时注意一下, 调度器的关闭顺序

13:02:05,625  INFO QuartzScheduler:666 - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED shutting down.
13:02:05,625  INFO QuartzScheduler:585 - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED paused.
13:02:05,626  INFO QuartzScheduler:740 - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED shutdown complete.

二.一.三 shutdown() 的参数

调用shutdown() 关闭方法时,也可以传入参数

void shutdown(boolean waitForJobsToComplete)  throws SchedulerException;

参数 true 和false, 是有一定的区别的, 下面检测一下。

二.一.三.一 任务调度里面添加 休眠

//shutdown 用法
public class MyJob10 implements Job {@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {//添加休眠,验证一下 shutdown(flag) 的参数try {Thread.sleep(5000);} catch (InterruptedException e) {// TODO 自动生成的 catch 块e.printStackTrace();}//要做的事,是打印当前的时间 SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//格式化时间String dateString=sdf.format(new Date());System.out.println("备份数据库的时间是:"+dateString);}
}

二.一.三.二 shutdown() 默认时

//shutdown 关闭
public class SchedulerDemo10 {public static void main(String[] args) throws  Exception{//获取SchedulerScheduler scheduler= StdSchedulerFactory.getDefaultScheduler();// 创建 JobDetailJobDetail jobDetail=JobBuilder.newJob(MyJob10.class).withIdentity("job1","group1").build();//创建 TriggerTrigger trigger= TriggerBuilder.newTrigger().withIdentity("trigger1","group1") //设置标识.startNow().withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(2)) // 设置为简单触发器.build();//关联 job和 triggerscheduler.scheduleJob(jobDetail,trigger);//启动 schedulerscheduler.start();//休眠10s后,关闭Thread.sleep(10000);//默认时scheduler.shutdown();}
}

控制台打印输出:

shutdown complete 在中间。

二.一.三.三 shutdown (false) 时

  //休眠10s后,关闭Thread.sleep(10000);// 为false 时scheduler.shutdown(false);

控制台打印输出:


shutdown complete 在中间。

结果,与默认时是一样的。

二.一.三.四 shutdown(true) 时

//休眠10s后,关闭
Thread.sleep(10000);
// 为true 时
scheduler.shutdown(true);

控制台打印输出:

shutdown complete 在最后。

当 shutdown() 方法 传入 true时, 表示会等所有任务队列里面的任务运行完成后,才关闭。 传入false时,是直接关闭。

注意,无论是直接关闭 false,还是等运行完成后关闭 true, 都不会影响任务队列里面的任务继续运行。

二.二 挂起 standby()

挂起并不是关闭,只是暂时停止运行, 等一段时间后,是可以再次 start() 开启的。

二.二.一 任务接口

//挂起
public class MyJob11 implements Job {@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {//要做的事,是打印当前的时间 SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//格式化时间String dateString=sdf.format(new Date());System.out.println("备份数据库的时间是:"+dateString);}
}

二.二.二 主程序测试

//挂起 standby
public class SchedulerDemo11 {public static void main(String[] args) throws  Exception{//获取SchedulerScheduler scheduler= StdSchedulerFactory.getDefaultScheduler();// 创建 JobDetailJobDetail jobDetail=JobBuilder.newJob(MyJob11.class).withIdentity("job1","group1").build();//创建 TriggerTrigger trigger= TriggerBuilder.newTrigger().withIdentity("trigger1","group1") //设置标识.startNow().withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(2)) // 设置为简单触发器.build();//关联 job和 triggerscheduler.scheduleJob(jobDetail,trigger);//启动 schedulerscheduler.start();//休眠10s后,挂起Thread.sleep(10000);scheduler.standby();//挂起10s后,重新开启Thread.sleep(10000);scheduler.start();}
}

二.二.三 控制台打印输出

挂起时间的那五次操作,又给补回来了,重复执行了5次。

如果这个任务执行的是数据库插入的操作,那么这个操作就会执行5遍,产生5条除id外相同的记录。

这样是不行的。

有没有一种方式,可以像数据库那样有个锁, 当队列里面有任务未执行结束时,不能进入?

有的,@DisallowConcurrentExecution 注解。

三. 作业任务的并发控制

并发控制,用的是 @DisallowConcurrentExecution 注解, 需要将这个注解放置到工作任务上, 就会形成类似锁的情形。

如果一个任务需要执行很长时间,并且触发器的触发时间较短,导致造成任务等待的问题,一定要处理并发控制。

注解路径: org.quartz.DisallowConcurrentExecution 。

三.一 任务接口

添加 @DisallowConcurrentExecution 注解, 并且休眠5s钟。

@DisallowConcurrentExecution
public class MyJob11 implements Job {@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {try {Thread.sleep(5000);} catch (InterruptedException e) {// TODO 自动生成的 catch 块e.printStackTrace();}//要做的事,是打印当前的时间 SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//格式化时间String dateString=sdf.format(new Date());System.out.println("备份数据库的时间是:"+dateString);}
}

三.二 主程序测试

触发时间为2s, 远远小于 休眠的5s, 会造成任务等待。

//挂起 standby
public class SchedulerDemo11 {public static void main(String[] args) throws  Exception{//获取SchedulerScheduler scheduler= StdSchedulerFactory.getDefaultScheduler();// 创建 JobDetailJobDetail jobDetail=JobBuilder.newJob(MyJob11.class).withIdentity("job1","group1").build();//创建 TriggerTrigger trigger= TriggerBuilder.newTrigger().withIdentity("trigger1","group1") //设置标识.startNow().withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(2)) // 设置为简单触发器.build();//关联 job和 triggerscheduler.scheduleJob(jobDetail,trigger);//启动 schedulerscheduler.start();//休眠10s后,挂起Thread.sleep(10000);scheduler.standby();//挂起10s后,重新开启Thread.sleep(10000);scheduler.start();}
}

三.三 控制台打印输出

并不会出现重复执行的问题。

三.四 shutdown() 时添加 @DisallowConcurrentExecution 注解

在 MyJob10.java 上面也添加这个注解

shutdown(false) 时运行程序:

shutdown(true) 时运行程序:

同样,可以达到并发控制的目的。

本章节代码链接为:


链接:https://pan.baidu.com/s/1XKV02pYcFxKU3GqcopziSA
提取码:dbk6

谢谢您的观看!!!

Quartz的Scheduler的关闭和挂起,并发控制(四)相关推荐

  1. Quartz的Scheduler初始化源码分析

    2019独角兽企业重金招聘Python工程师标准>>> Quartz的使用:http://donald-draper.iteye.com/blog/2321886  Quartz的S ...

  2. Quartz 2 Scheduler示例

    Quartz是一个开源作业调度框架. 它可用于管理和计划应用程序中的作业. 步骤1:建立已完成的专案 创建一个Maven项目,如下所示. (可以使用Maven或IDE插件来创建它). 步骤2:图书馆 ...

  3. nohup和的使用/21是什么意思/怎么关闭nohup挂起的程序

    1.&和nohup和2>&1的定义: & 放在命令到结尾,表示后台运行,防止终端一直被某个进程占用,这样终端可以执行别到任务 nohup放在命令的开头,表示不挂起(no ...

  4. ubuntu18.04关闭自动挂起和锁屏

    关闭自动挂起: 设置→电源→挂起和关机按钮→关 关闭自动锁屏: 设置→隐私→锁屏

  5. 神舟笔记本触摸板驱动_关闭笔记本触摸板的四种方法

    从某种意义上说,触摸板的使用,能够帮助我们解放一部分的工作.但是很多时候,我们都会用不到触摸板,因为我们还是会使用鼠标更多.这时,触摸板的存在就会显得有点碍事,因为我们会出现误触的情况.这时,我们就要 ...

  6. 实战Quartz的Scheduler

    一 点睛 1 Scheduler是通过工厂模式创建的. 所有的Scheduler实例由SchedulerFactory来创建. 2 Quartz的三个核心概念 调度器 任务 触发器 3 Schedul ...

  7. Spring的Tomcat服务关闭后,Quartz进程无法正常关闭,出现内存泄露

    简介 spring内部整合quartz,将quartz整合到web项目里面,通过页面动态控制quartz的增加.修改.删除.查询,这种方式极大简化了对quartz定时器任务的控制: 但随之而来的是一个 ...

  8. java quartz tomcat_Quartz Scheduler - 在Tomcat或应用程序jar中运行?

    我们有一个Web应用程序,它通过在Jersey / Tomcat / Apache / PostgreSQL上运行的RESTful Web服务接收传入数据 . 与此Web服务应用程序分开,我们需要执行 ...

  9. 【问题1】为什么连接的时候是三次握手,关闭的时候却是四次握手?

    答:三次握手是因为因为当Server端收到Client端的SYN连接请求报文后,可以直接发送SYN+ACK报文.其中ACK报文是用来应答的,SYN报文是用来同步的.但是关闭连接时,当Server端收到 ...

最新文章

  1. SSM框架——Spring+SpringMVC+Mybatis的搭建教程
  2. 调查:中国CIO在亚太拥最大战略影响力
  3. 基本数据类型转换 || 自动类型转换与强制类型转换
  4. ubuntu14.04交叉编译vlc2.1.5源码,编译出在win32下运行的程序
  5. [Swift]数组排序:sort和sorted
  6. java怎么看dao文件_java通过实体类生成dao文件
  7. 前端学习(392):京东制作页面1京东项目项目介绍
  8. c盘不能新建文件的解决办法
  9. C++多线程同步之Semaphore(信号量)
  10. WiFi图标在任务栏里不见了,提示:适配器Qualcomn Atheros QCA9377 Wireless Network Adapter遇到驱动程序或硬件相关的问题
  11. 中国安检设备行业市场发展分析及前景趋势展望报告2022-2028年
  12. 微信公众号文章信息(阅读量、在看、点赞数)获取
  13. php取网盘真实链接,利用蓝奏做个人小文件网盘和获取真实下载地址
  14. ORACLE学习详解
  15. MATLAB矩阵分块拼装
  16. java对接支付宝(四)-即时到账无秘退款
  17. p2p金融项目+支付宝充值
  18. [附源码]Python计算机毕业设计Django自行车租赁管理系统
  19. 【010】汉典-纯粹的汉语字典数据库
  20. Direct2D教程II——绘制基本图形和线型(StrokeStyle)的设置详解

热门文章

  1. CCNP-WLAN无线配置实验
  2. Matlab mod函数 对应C语言 函数
  3. 喝酒神器新UI版本带特效和音效,缩减版本微信小程序源码下载
  4. 实物溯源再添新彩|众享比特获评2020年度中国食品追溯优秀供应商
  5. mmdet_config_builder_win
  6. AirPlay视频认证测试用例
  7. 四元数欧拉角转换工具
  8. 【软考系统架构设计师】2014年下系统架构师论文写作历年真题
  9. 健身 | 无器材如何练手臂肌肉?最简单几个动作
  10. JAVAEE model1模型实现商品浏览记录(去除重复的浏览记录)(一)