Java定时任务调度工具详解之Timer
导航:
一. 概述
1.1 课程介绍
-
什么是定时任务调度:
- 基于给定的时间点,给定的时间间隔或者给定的执行次数自动执行的任务
-
Java中的定时任务调度工具
- Timer
- Quartz
-
不同点:
- 出身不同,Timer是自带的,Quartz是需要引入的
- 能力不同,Timer解决不了的,Quartz可以解决
- 底层机制,Quartz比Timer好,但是Quartz的配置难一点
-
需要准备的知识:
- Timer,Quartz的使用 ->Java基础知识
- Quartz,Spring的合体 ->Spring基础知识
1.2 Timer简介
-
Timer的定义:
- 有且仅有一个后台线程对多个业务线程进行定时定频率的调度
-
主要构件:
- Timer—>Time Task (定时调度定时任务)
-
工具类详解
1.3 实战演练
- MyTimerTask.java
import java.util.TimerTask
public class MyTimerTask extends TimerTask{
private String name;
public MyTimerTask(String inputName){
name=inputName;
}
@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;
}
}
- 创建 MyTimer.java
import java.util.Timer
public class MyTimer{
public static void main(String[] args){
//1. 创建一个Timer实例
Timer timer=new Timer();
//2. 创建一个MyTimerTask实例
MyTimerTask myTimerTask=new MyTimeTask("No.1");
//3. 通过Timer定时定频率调用myTimerTask的业务逻辑
//即第一次执行是在当前时间的两秒之后,之后每隔一秒钟执行一次
timer.schedule(myTimerTask,2000L,1000L);
}
}
二. timer定时函数的用法
2.1 schedule的四种用法
- schedule(task,time):
- 参数:
- task->所要安排的任务
- time->执行任务的时间
- 作用:
- 在时间等于或者超过time的时候执行且仅执行一次task
- 在时间等于或者超过time的时候执行且仅执行一次task
- 参数:
在具体的时间执行一次;
- suchedult(task,time,period)
-
参数:
- task: 所要安排的任务
- time: 首次执行任务的时间
- period: 执行一次task的时间间隔,单位是毫秒
-
作用:
- 时间等于或超过time时首次执行task
- 之后每隔period毫秒重复执行一次task
-
- 实战代码:
使用此schedule,就会从calendar.getTime()时间开始起,每隔2000毫秒执行一次;
-
schedule(task,delay)
- 作用:
- 等待delay毫秒后执行且执行一次task
- 效果图:
- 作用:
-
schedule(task,delay,period)
- 作用:
- 等待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
- 效果图:
- 参数:
三. 其他重要函数
3.1 本节内容
- TimerTask的cancel(),scheduledExcetionTime()
- Timer的cancel(),purge()
3.2 代码示例:
这里在自定义的Timer代码里面,使用count定义一个计数器,当count到达3的时候,则执行cancel()方法取消定时任务运行;
3.3 scheduledExecutionTime()
- 作用:
- 返回此任务最近实际执行的已安排执行的时间
- 返回值:
- 最近发生此任务执行安排的时间,为long型
返回离我们最近的一次任务的执行时间
- 展示执行后的效果如下:
3.4 Timer的其他函数
- cancel() ->这个cancel是隶属于Timer之下的,与之前的是有区别的
- 作用: 终止此计时器,丢弃所有当前已安排的任务
- 图示如下:
使用timer.cancel则会使得Timer timer=new Timer();中的timer终止它的所有定时任务;
3.5 purge()
- 返回值:从队列中移除的任务数,并且将这个任务从当前队列移除
- 效果图:
使用purge()返回的不是当前任务数,而是返回被取消的任务数有多少个,并且将这个任务从当前队列移除
四. schedule与scheduleAtFixedRate的区别
4.1 两种情况看区别
- 首次计划执行的时间早于当前的时间(比如第一次任务执行时间早于当前时间)
- 任务执行所需时间超出任务的执行周期间隔(比如我们一个定时任务每隔2秒钟执行一次,但是每次执行需要耗费3秒)
4.2 具体区别----首次计划执行的时间早于当前的时间
- schedule方法
- “fixed-delay”:如果第一次执行时间被delay(提前)了,随后的执行时间按照上一次实际执行完成的时间点进行计算
- scheduleAtAFixedRate方法
- “fixed-rate”: 如果第一次执行时间被delay了,随后的执行时间按照上一次开始的时间点进行计算,并且为了赶上进度会多次执行任务,因此TimerTask中的执行体需要考虑同步;
4.2 具体区别----任务执行所需时间超出任务的执行周期间隔
-
schedule方法
- 下一次执行时间相对于上一次实际执行完成的时间点,因此执行时间会不断延后
-
scheduleAtFixedRate方法
- 下一次执行时间相对于上一次开始的时间点,因此执行时间一般不会延后,因此存在并发性;
scheduleAtFixedRate更加精确,但是如果存在执行任务所需时间大于任务调度间隔时间,则容易两个任务并行进行,即可能存在并发问题;
- 效果图:
可以看到,scheduleAtFixedRate更加精确,严格按照设置的每2秒钟执行一次,并不会受到任务耗时所影响,而schedule是根据上一次的成功执行时间然后延后2秒,严格上来讲,这两个是有本质区别的;
五. Timer函数的综合应用
5.1 主要内容
- 通过模拟两个机器人的定时行为来把我们前面所学的主要函数结合起来,让大家加深对这些函数的理解;
5.2 实现两个机器人
- 第一个机器人会隔2秒打印最近一次计划的时间、执行内容
- 第二个机器人会模拟往桶里倒水,直到桶里水满为止;
5.4 灌水机器人的执行流程
- 图示:
5.5 跳舞机器人的执行流程
- 图示:
5.6 代码演示:
- WaterRobot.java:
public class WaterRobot extends TimerTask{
private Timer timer;
//最大容量为5L
private Integer bucketCapacity=0;
public WaterRobot(Timer inputTimer){
timer=inputTimer;
}
@Override
public void run(){
//灌水直到桶满为止
if(bucketCapacity<5){
System.out.println("Add 1L water into the bucket!");
bucketCapacity++;
}else{
//水满了之后停止执行
cancel();
System.out.println("The waterRobot has been aborted");
//等待2秒钟,终止timer里面的所有内容
try{
Thread.sleep(2000);
}catch(InterruptedException e){
e.printStackTrace();
}
timer.cancel();
}
}
}
- Executor.java [执行定时任务]
public class Executor{
public static void main(String[] args)throws InterruptedException{
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()));
timer.schedule(dr,calendar.getTime(),2000);
timer.scheduleAtFixedRate(wr,calendar.getTime(),1000);
}
}
跳舞机器人可以自己来实现;
六. Tiemr的缺陷
6.1 天生的两种缺陷
- 管理并发任务的缺陷
- Timer有且仅有一个线程去执行定时任务,如果存在多个任务,且任务时间过长,会导致执行效果与预期不符;
- 当任务抛出异常时的缺陷
- 如果TimerTask 抛出RuntimeException,Timer会停止所有任务的运行
6.2 Timer的使用禁区
- 对时效性要求较高的多任务并发作业
- 对复杂的任务的调度
如果对这两方面有要求的,可以使用quartz或者集成的分布式任务调度框架;