时间:2017年05月24日星期三
说明:本文部份内容均来自慕课网。@慕课网:http://www.imooc.com
教学示例源码:无
我的学习源码:https://github.com/zccodere/s...java
什么是定时任务调度git
基于给定的时间点,给定的时间间隔或者给定的执行次数自动执行的任务
在Java中的定时调度工具github
Timer:小弟,能实现平常60%的定时任务 Quartz:大哥,能搞定一切
Timer与Quartz区别架构
出身不一样 Timer由JDK提供,调用方式简单粗暴,不须要别的jar包支持 Quartz源于开源项目,非JDK自带,须要引入别的jar包支持 能力区别:主要体如今对时间的控制上 Timer实现如某个具体时间执行什么任务 Quartz实现如每一个星期天8点执行什么任务 Quartz的时间控制功能远比Timer强大和完善 底层机制 Timer走后台线程执行定时任务 Quartz可以使用多个执行线程去执行定时任务 Quartz确实比Timer强大不少,可是,Timer能实现的功能,尽可能不动用Quartz 毕竟大哥的出场费要比小弟高
前置知识并发
本节内容app
Timer纸上谈兵:Timer的定义以及架构 Timer实战演练:经过一个实际的例子,让你们对Timer有一个初步的了解
Timer的定义ide
有且仅有一个后台线程对多个业务线程进行定时定频率的调度
主要构件函数
Timer工具类详解工具
经过程序来说解Timer学习
代码演示
1.编写需定时调度的业务逻辑类
package com.myimooc.timer; import java.util.TimerTask; /** * 需定时调度的业务逻辑类 * Created by ChangComputer on 2017/5/24. */ // 继承 TimerTask 类 public class MyTimerTask extends TimerTask{ private String name; public MyTimerTask(String name){ this.name = name; } // 重写 run 方法 @Override public void run() { // 打印当前 name 的内容 System.out.println("Current exec name is : " + name); } public String getName() { return name; } public void setName(String name) { this.name = name; } }
2.编写定时调度类
package com.myimooc.timer; import java.util.Timer; /** * 定时调度类 * Created by ChangComputer on 2017/5/24. */ public class MyTimer { public static void main(String[] args){ // 建立一个 Timer 实例 Timer timer = new Timer(); // 建立一个 MyTimerTask 实例 MyTimerTask myTimerTask = new MyTimerTask("No.1"); // 经过 Timer 定时定频率调用 MyTimerTask 的业务逻辑 // 即第一次执行是在当前时间的两秒以后,以后每隔一秒钟执行一次 timer.schedule(myTimerTask,2000L,1000L); } }
本节内容
schedule的四种用法 scheduleAtFixedRate的两种用法
第一种用法:schdule(task, time)
参数 task:所要安排的任务 time:执行任务的时间 做用 在时间等于或者超过time的时候执行且仅执行一次task
第二种用法:schedule(task, time, period)
参数 task:所要安排的任务 time:首次执行任务的时间 period:执行一次task的时间间隔,单位是毫秒 做用 时间等于或者超过time时首次执行task 以后每隔period毫秒重复执行一次task
第三种用法:schedule(task, delay)
参数 task:所要安排的任务 delay:执行任务前的延迟时间,单位是毫秒 做用 等待delay毫秒后仅执行且执行一个task
第四种用法:schedule(task, delay, period)
参数 task:所要安排的任务 delay:执行任务前的延迟时间,单位是毫秒 period:执行一次task的时间间隔,单位是毫秒 做用 等到delay毫秒后首次执行task 以后每隔period毫秒重复执行一次task
第一种用法:scheduleAtFixedRate(task, time, period)
参数 task:所要安排的任务 time:首次执行任务的时间 period:执行一次task的时间间隔,单位是毫秒 做用 时间等于或超过time时首次执行task 以后每隔period毫秒重复执行一次task
第二种用法:scheduleAtFixedRate(task, delay, period)
参数 task:所要安排的任务 delay:执行任务前的延迟时间,单位是毫秒 period:执行一次task的时间间隔,单位是毫秒 做用 等到delay毫秒后首次执行task 以后每隔period毫秒重复执行一次task
代码演示
1.修改需定时调度的业务逻辑类
/** * 需定时调度的业务逻辑类 * Created by ChangComputer on 2017/5/24. */ // 继承 TimerTask 类 public class MyTimerTask extends TimerTask{ private String name; public MyTimerTask(String name){ this.name = name; } // 重写 run 方法 @Override public void run() { // 以yyyy-MM-dd HH:mm:ss的格式打印当前执行时间 // 如2016-11-11 00:00:00 Calendar calendar = Calendar.getInstance(); // 定义日期格式 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("Current exec time is : " + simpleDateFormat.format(calendar.getTime())); // 打印当前 name 的内容 System.out.println("Current exec name is : " + name); } public String getName() { return name; } public void setName(String name) { this.name = name; } }
2.修改定时调度类
package com.myimooc.timer; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Timer; /** * 定时调度类 * Created by ChangComputer on 2017/5/24. */ public class MyTimer { public static void main(String[] args){ // 建立一个 Timer 实例 Timer timer = new Timer(); // 建立一个 MyTimerTask 实例 MyTimerTask myTimerTask = new MyTimerTask("No.1"); // 经过 Timer 定时定频率调用 MyTimerTask 的业务逻辑 // 即第一次执行是在当前时间的两秒以后,以后每隔一秒钟执行一次 //timer.schedule(myTimerTask,2000L,1000L); /** * 获取当前时间,并设置成距离当前时间三秒以后的时间 * 如当前时间是2016-11-10 23:59:57 * 则设置后的时间则为2016-11-11 00:00:00 */ Calendar calendar = Calendar.getInstance(); // 定义日期格式 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("Current exec time is : " + simpleDateFormat.format(calendar.getTime())); calendar.add(Calendar.SECOND,3); // schedule的四种用法 /** * 1.在时间等于或超过time的时候执行仅且执行一次task * 如在2016-11-11 00:00:00执行一次task,打印任务名字 */ //myTimerTask.setName("schedule1"); //timer.schedule(myTimerTask,calendar.getTime()); /** * 2.时间等于或超过time首次执行task * 以后每隔period毫秒重复执行一次task * 如在2016-11-11 00:00:00第一次执行task,打印任务名字 * 以后每隔两秒执行一次task */ //myTimerTask.setName("schedule2"); //timer.schedule(myTimerTask,calendar.getTime(),2000L); /** * 3.等待delay毫秒后仅执行且执行一个task * 如如今是2016-11-11 00:00:00 * 则在2016-11-11 00:00:01执行一次task,打印任务名字 */ //myTimerTask.setName("schedule3"); //timer.schedule(myTimerTask,1000L); /** * 4.等到delay毫秒后首次执行task * 以后每隔period毫秒重复执行一次task * 如如今是2016-11-11 00:00:00 * 则在2016-11-11 00:00:01第一次执行task,打印任务名字 * 以后每隔两秒执行一次task */ //myTimerTask.setName("schedule4"); //timer.schedule(myTimerTask,1000L,2000L); // scheduleAtFixedRate的两种用法 /** * 1.时间等于或超过time时首次执行task * 以后每隔period毫秒重复执行一次task * 如在2016-11-11 00:00:00第一次执行task,打印任务名字 * 以后每隔两秒执行一次task */ //myTimerTask.setName("scheduleAtFixedRate1"); //timer.scheduleAtFixedRate(myTimerTask,calendar.getTime(),2000L); /** * 2.等待delay毫秒后首次执行task * 以后每隔period毫秒重复执行一次task * 如如今是2016-11-11 00:00:00 * 则在2016-11-11 00:00:01第一次执行task,打印任务名字 * 以后每隔两秒执行一次task */ myTimerTask.setName("scheduleAtFixedRate2"); timer.scheduleAtFixedRate(myTimerTask,1000L,2000L); } }
本节内容
TimerTask的cancel(), scheduleExecutionTime() Timer的cancel(), purge()
TimerTask类的cancel()
做用 取消当前TimerTask里的任务
TimerTask类的scheduleExecutionTime()
做用 返回此任务最近实际执行的已安排执行的时间 返回值 最近发生此任务执行安排的时间,为long型
Timer的cancel()
做用 终止此计时器,丢弃全部当前已安排的任务
Timer的purge()
做用 今后计时器的任务队列中移除全部已取消的任务 返回值 从队列中移除的任务数
代码演示
package com.myimooc.timer; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Timer; /** * Created by ChangComputer on 2017/5/24. */ public class CancelTest { public static void main(String[] args) throws InterruptedException { // 建立Timer实例 Timer timer = new Timer(); // 建立TimerTask实例 MyTimerTask task1 = new MyTimerTask("task1"); MyTimerTask task2 = new MyTimerTask("task2"); // 获取当前的执行时间并打印 Date startTime = new Date(); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("start time is : " + simpleDateFormat.format(startTime)); // task1首次执行是距离如今时间3秒后执行,以后每隔2秒执行一次 // task1首次执行是距离如今时间1秒后执行,以后每隔2秒执行一次 timer.schedule(task1,3000L,2000L); timer.schedule(task2,1000L,2000L); System.out.println("current canceled task number is : " + timer.purge()); // 休眠5秒 Thread.sleep(2000L); // 获取当前的执行时间并打印 Date cancelTime = new Date(); System.out.println("cancel time is : " + simpleDateFormat.format(cancelTime)); // 取消全部任务 // timer.cancel(); task2.cancel(); //System.out.println("Tasks all canceled!"); System.out.println("current canceled task number is : " + timer.purge()); } }
两种状况看区别
首次计划执行的时间早于当前的时间 任务执行所需时间超出任务的执行周期间隔
首次计划执行的时间早于当前的时间
1.schedule方法 “fixed-delay”,若是第一次执行时间被delay了, 随后的执行时间按照上一次实际执行完成的时间点进行计算 2.scheduleAtFixedRate方法 “fixed-rate”,若是第一次执行时间被delay了, 随后的执行时间按照上一次开始的时间点进行计算, 而且为了遇上进度会屡次执行任务,所以TimerTask中的执行体须要考虑同步
代码演示
package com.myimooc.timer; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Timer; import java.util.TimerTask; /** * schedule和scheduleAtFixedRate的区别 测试类 * Created by ChangComputer on 2017/5/24. */ public class DifferenceTest { public static void main(String[] args){ // 定义时间格式 final SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 获取当前的具体时间 Calendar calendar = Calendar.getInstance(); System.out.println("Current time is : " + sf.format(calendar.getTime())); // 设置成6秒前的时间,若当前时间为2016-12-28 00:00:06 // 那么设置以后时间变成2016-12-28 00:00:00 calendar.add(Calendar.SECOND,-6); Timer timer = new Timer(); // 第一次执行时间为6秒前,以后每隔两秒钟执行一次 //timer.schedule(new TimerTask() { timer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { // 打印当前的计划执行时间 System.out.println("Schedule exec time is : " + sf.format(scheduledExecutionTime())); System.out.println("Task is being executed!"); } }, calendar.getTime(), 2000); } }
任务执行所需时间超出任务的执行周期间隔
1. schedule方法 下一次执行时间相对于上一次实际执行完成的时间点,所以执行时间会不断延后 2.scheduleAtFixedRate方法 下一次执行时间相对于上一次开始的时间点,所以执行时间通常不会延后,所以存在并发性
代码演示
package com.myimooc.timer; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Timer; import java.util.TimerTask; /** * schedule和scheduleAtFixedRate的区别 测试类 * Created by ChangComputer on 2017/5/24. */ public class DifferenceTwoTest { public static void main(String[] args){ // 定义时间格式 final SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // 获取当前的具体时间 Calendar calendar = Calendar.getInstance(); System.out.println("Current time is : " + sf.format(calendar.getTime())); Timer timer = new Timer(); //timer.schedule(new TimerTask() { timer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { try { Thread.sleep(3000L); } catch (InterruptedException e) { e.printStackTrace(); } // 打印最近一次的计划执行时间 System.out.println("Schedule exec time is : " + sf.format(scheduledExecutionTime())); System.out.println("Task is being executed!"); } }, calendar.getTime(), 2000); } }
主要内容
经过模拟两个机器人的定时行为来把前面所学的主要函数给结合起来,让你们加深对这些函数的理解
实现两个机器人
第一个机器人会隔两秒打印最近一次计划的时间、执行内容 第二个机器人会模拟往桶里倒水,直到桶里的水满为止
灌水机器人的执行流程
跳舞机器人的执行流程
代码演示
1.建立跳舞机器人
package com.myimooc.timer; import java.text.SimpleDateFormat; import java.util.TimerTask; /** * 跳舞机器人 * Created by ChangComputer on 2017/5/24. */ public class DancingRobot extends TimerTask{ /** * 任务执行 * */ @Override public void run() { // 获取最近的一次任务执行的时间并将其格式化 SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.print("Schduled exec time is : " + sf.format(scheduledExecutionTime())); System.out.println("Dancing happily!"); } }
2.建立灌水机器人
package com.myimooc.timer; import java.util.Timer; import java.util.TimerTask; /** * 灌水机器人 * Created by ChangComputer on 2017/5/24. */ public class WaterRobot extends TimerTask{ private Timer timer; // 桶容量,最大容量为5 private Integer bucketCapacity = 0; public WaterRobot(Timer timer){ this.timer = timer; } @Override public void run() { // 灌水直至桶满为止 if (this.bucketCapacity < 5) { System.out.println("Add 1L water into the bucket!"); bucketCapacity++; }else{ System.out.println("The number of canceled task in timer is : " + timer.purge()); // 水满以后就中止执行 cancel(); System.out.println("The waterRobot has been aborted"); System.out.println("The number of canceled task in timer is : " + timer.purge()); System.out.println("Current water is : " + bucketCapacity); // 等待两秒钟,终止timer里面的全部内容 try { Thread.sleep(2000L); } catch (InterruptedException e) { e.printStackTrace(); } timer.cancel(); } } }
3.建立执行类
package com.myimooc.timer; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Timer; /** * 机器人执行类 * Created by ChangComputer on 2017/5/24. */ public class RobotExecutor { public static void main(String[] args){ Timer timer = new Timer(); // 获取当前时间 Calendar calendar = Calendar.getInstance(); SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); System.out.println("Current time is : " + sf.format(calendar.getTime())); DancingRobot dancingRobot = new DancingRobot(); WaterRobot waterRobot = new WaterRobot(timer); timer.schedule(dancingRobot,calendar.getTime(),2000L); timer.scheduleAtFixedRate(waterRobot,calendar.getTime(),1000L); } }
Timer天生的两种缺陷
管理并发任务的缺陷
Timer有且仅有一个线程去执行定时任务,若是存在多个任务,且任务时间过长,会致使执行效果与预期不符
当任务抛出异常时的缺陷
若是TimerTask抛出RuntimeException,Timer会中止全部任务的运行
Timer的使用禁区
对时效性要求较高的多任务并发做业 对复杂任务的调度