笔记来源:IMOOC Java Timer
定时任务调度
- 基于给定的时间点,给定的时间间隔或者给定的执行次数自动执行的任务。
Timer 定义
- 一种工具,线程用其安排以后在后台线程中执行的任务。可安排任务执行一次,或者定期重复执行。
- 有且仅有一个后台线程对多个业务线程进行定时定频率的调度。
Timer 主要构建
Timer 主要成分
Timer 定时调度函数
schedule 的四种用法
-
schedule(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 的两种用法
-
scheduleAtFixedRate(task, time, period)
-
参数
- task - 所要安排的任务
- time - 首次执行任务的时间
- period - 执行一次task的时间间隔,单位是毫秒
-
作用
- 时间等于或超过time时首次执行task,之后每隔period毫秒重复执行一次task
-
-
scheduleAtFixedRate(task, delay, period)
-
参数
- task - 所要安排的任务
- delay - 执行任务前的延迟时间,单位是毫秒
- period - 执行一次task的时间间隔,单位是毫秒
-
作用
- 等待delay毫秒后首次执行task,之后每隔period毫秒重复执行一次task
-
Timer 示例
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.TimerTask;
public class MyTimerTask extends TimerTask {
private String name;
public MyTimerTask(String inputName) {
name = inputName;
}
@Override
public void run() {
// 以 yyyy-MM-dd HH:mm:ss 的格式打印当前执行时间
Calendar calendar = Calendar.getInstance();
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("Current exec time is: " + sf.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;
}
}
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Timer;
public class MyTimer {
public static void main(String[] args) {
// 1. 创建一个timer实例
Timer timer = new Timer();
// 2. 创建一个MyTimerTask实例
MyTimerTask myTimerTask = new MyTimerTask("No.1");
/**
* 获取当前时间,并设置成距离当前时间三秒后的时间
*/
Calendar calendar = Calendar.getInstance();
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("Current main time is: " + sf.format(calendar.getTime()));
calendar.add(Calendar.SECOND, 3);
// 3. 通过timer定时定频率调用myTimerTask的业务逻辑
//-------------------schedule的四种用法-------------------//
/**
* 在时间等于或超过time的时间执行且仅执行一次task
*/
myTimerTask.setName("schedule_1");
timer.schedule(myTimerTask, calendar.getTime());
/**
* 时间等于或超过time时首次执行task,之后每隔period毫秒重复执行一次task
*/
myTimerTask.setName("schedule_2");
timer.schedule(myTimerTask, calendar.getTime(), 2000);
/**
* 等待delay毫秒后执行且仅执行一次task
*/
myTimerTask.setName("schedule_3");
timer.schedule(myTimerTask, 1000);
/**
* 等待delay毫秒后首次执行task,之后每隔period毫秒重复执行一次task
*/
myTimerTask.setName("schedule_4");
timer.schedule(myTimerTask, 3000, 2000);
//--------------scheduleAtFixedRate的两种用法-------------//
/**
* 时间等于或超过time时首次执行task,之后每隔period毫秒重复执行一次task
*/
myTimerTask.setName("scheduleAtFixedRate_1");
timer.scheduleAtFixedRate(myTimerTask, calendar.getTime(), 2000);
/**
* 等待delay毫秒后首次执行task,之后每隔period毫秒重复执行一次task
*/
myTimerTask.setName("scheduleAtFixedRate_2");
timer.scheduleAtFixedRate(myTimerTask, 3000, 2000);
}
}
schedule 与 scheduleAtFixedRate 的区别
首次计划执行的时间早于当前的时间
-
schedule
方法-
fixed-delay
;如果第一次执行时间被 delay 了,随后的执行时间按照上一次实际执行完成的时间点进行计算
-
-
scheduleAtFixedRate
方法-
fixed-rate
;如果第一次执行时间被 delay 了,随后的执行时间按照上一次开始的时间点进行计算,并且为了赶上进度会多次执行任务,因此TimerTask
中的执行体需要考虑同步
-
任务执行所需时间超出任务的执行周期间隔
-
schedule
方法- 下一次执行时间相对于上一次实际执行完成的时间点,因此执行时间会不断延后
-
scheduleAtFixedRate
方法- 下一次执行时间相对于上一次开始的时间点,因此执行时间一般不会延后,因此存在并发性
其他重要函数
-
TimerTask
的cancel()
、scheduleExecutionTime()
-
Timer
的cancel()
、purge()
TimerTask 的两个重要函数
-
cancel()
- 作用:取消当前
TimerTask
里的任务
- 作用:取消当前
-
scheduleExecutionTime()
- 作用:返回此任务最近实际执行的已安排执行的实际
- 返回:最近发生此任务执行安排的时间,为Long类型
Timer 的其他函数
-
cancel()
- 终止此计时器,丢弃所有当前已安排的任务
-
purge()
- 作用:从此计时器的任务队列中移除所有已取消的任务
- 返回:从队列中移除的任务数
Timer 函数的综合应用
-
模拟两个机器人的定时行为
- 第一个机器人会隔两秒打印最近一次计划的时间、执行内容
- 第二个机器人会模拟往桶里倒水,直到桶里的水满为止,然后停止工作
- 桶里的水满了之后,第一个机器人再跳舞两秒钟,然后停止工作
/**
* 跳舞的机器人
*/
public class DancingRobot extends TimerTask {
@Override
public void run() {
// 获取最近的一次任务执行的时间,并将其格式化
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("Scheduled exec time is: " + sf.format(scheduledExecutionTime()));
System.out.println("Dancing happily!");
}
}
/**
* 倒水的机器人
*/
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 {
// 水满之后就停止执行
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 + "L");
// 等待两秒钟,终止timer里面的所有内容
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
timer.cancel();
}
}
}
public class Executor {
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 dr = new DancingRobot();
WaterRobot wr = new WaterRobot(timer);
timer.schedule(dr, calendar.getTime(), 2000);
timer.scheduleAtFixedRate(wr, calendar.getTime(), 1000);
}
}
Timer 的缺陷
-
管理并发任务的缺陷
- Timer 有且只有一个线程去执行定时任务,如果存在多个任务,且任务时间过长,会导致执行效果与预期不符
-
当任务抛出异常时的缺陷
- 如果
TimerTask
抛出RuntimeException
,Timer 会停止所有任务的运行
- 如果
Timer 的使用禁区
- 对时效性要求较高的多任务并发作业
- 对复杂的任务的调度
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。