Timer和TimerTask类
Timer和TimerTask类可以看做是实现线程的第三种方式。Timer类是Java定时器类,可保证多个线程共享一个Timer类对象而无需进行外部的同步,所以Timer类是线程安全的。
Timer类
Timer实际上是一个线程,定时调度所有的TimerTask类对象。
构造方法
Timer类有多种构造方法,
构造方法 | 参数说明 |
---|---|
Timer() | 创建一个计时器 |
Timer(boolean isDaemon) | 创建一个计时器,可以指定其线程作为守护进程运行 |
Timer(String name) | 创建一个指定名称的计时器 |
Timer(String name, boolean isDaemon) | 创建一个计时器,并赋予其指定名称,同时设置守护进程的方式运行 |
schedule和scheduleAtFixedRate方法
schedule方法
schedule方法的调用形式有多种,关键的两个参数为,
参数 | 说明 |
---|---|
delay | 延迟执行的毫秒数,即在delay毫秒后第一次执行 |
period | 重复执行的时间间隔 |
/* time为Date类型,在指定时间执行一次*/
timer.schedule(TimerTask task, Date time)
/* firstTime为Date类型,period为long,
在firstTime时刻第一次执行,之后每隔period毫秒执行一次*/
timer.schedule(TimerTask task, Date firstTime, long period)
/* delay为long类型,从当前开始delay毫秒后执行一次*/
timer.schedule(TimerTask task, long delay)
/* delay为long类型,period为long,
从当前开始delay毫秒后执行一次,之后每隔period毫秒执行一次*/
timer.schedule(TimerTask task, long delay, long period)
scheduleAtFixedRate方法
scheduleAtFixedRate方法的功能域schedule方法相同,都是定时执行任务,二者之间的区别在之后会说明,该方法的关键参数与schedule方法一样都是delay和period。调用主要有两种形式,
/* 指定的时间第一次执行,之后每隔period毫秒执行一次*/
scheduleAtFixedRate(TimerTask task, Date firstTime, long period)
/* 从现在算起delay毫秒之后执行,之后每隔period毫秒执行一次*/
scheduleAtFixedRate(TimerTask task, long delay, long period)
TimerTask类
TimerTask类是一个抽象类,由Timer类安排其第一次执行和重复执行的时间。Timer类有一个抽象方法run方法,该方法内存放定时执行的代码。每个具体的任务类都必须继承TimerTask并重写其run方法。
TimerTask类中存在两个非抽象方法,
方法 | 说明 |
---|---|
boolean cancel() | 取消此任务 |
long scheduledExecutionTime() | 返回此任务最近一次执行的时间 |
实例代码
定义定期被执行的任务类
实现一个TimeTask的子类,
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.TimerTask;
public class MyTimerTask extends TimerTask {
private String name;
public MyTimerTask(String name) {
this.name = name
}
@override
public void run() {
Calendar calendar = Calendar.getInstance();
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("current execute time is: " + sf.format(calendar.getTime()));
System.out.println("current exec name is: " + this.name);
}
}
定时任务器
import java.util.Timer;
public class MyTimer {
public static void main(String[] args) {
// 创建Timer实例
Timer timer = new Timer();
// 创建TimerTask实例
MyTimerTask myTimerTask = new MyTimerTask("No.1");
// 两秒后第一次执行,之后每隔一秒执行一次
timer.schedule(myTimerTask, 2000, 1000);
}
}
输出结果如下,
current exec time is:2019-07-30 14:35:22
current exec name is:No.1
current exec time is:2019-07-30 14:35:23
current exec name is:No.1
current exec time is:2019-07-30 14:35:24
current exec name is:No.1
schedule与scheduleAtFixedRate方法的区别
方法 | 差异 |
---|---|
schedule | 更注重保持时间间隔的稳定,保证每隔period毫秒可调用一次 |
scheduleAtFixedRate | 更注重保持频率的稳定,保证多次调用的频率趋近period毫秒。如果任务执行的间隔大于period时,会立即执行下一次任务。 |
schedule方法
还是上方的MyTimerTask类的任务为例,
- 在时间等于或超过time的时候执行,且只执行一次
public class MyTimer {
public static void main(String[] args) {
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()));
// 设置Calendar的时间比当前实际时间快3秒
calendar.add(Calendar.SECOND, 3);
Timer timer = new Timer();
MyTimerTask myTimerTask = new MyTimerTask("schedule1");
timer.schedule(myTimerTask, calendar.getTime());
}
}
返回结果,
current exec time is:2019-07-30 15:46:16
current exec time is:2019-07-30 15:46:19
Current exec name is:schedule1
执行时的时间显示在第一行,三秒钟后任务被执行且仅执行一次。
- 时间等于或超过 time 的时候首次执行,之后每隔 period 毫秒重复执行一次 task
public class MyTimer {
public static void main(String[] args) {
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()));
// 设置Calendar的时间比当前实际时间快3秒
calendar.add(Calendar.SECOND, 3);
Timer timer = new Timer();
MyTimerTask myTimerTask = new MyTimerTask("schedule2");
timer.schedule(myTimerTask, calendar.getTime(), 3000);
}
}
返回结果,
current exec time is:2019-07-30 15:54:32
current exec time is:2019-07-30 15:54:35
Current exec name is:schedule2
current exec time is:2019-07-30 15:54:38
Current exec name is:schedule2
current exec time is:2019-07-30 15:54:41
Current exec name is:schedule2
- 等待 delay 毫秒之后执行且执行一次 task
public class MyTimer {
public static void main(String[] args) {
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()));
Timer timer = new Timer();
MyTimerTask myTimerTask = new MyTimerTask("schedule3");
timer.schedule(myTimerTask, 1000);
}
}
current exec time is:2019-07-30 16:00:06
current exec time is:2018-06-05 16:00:07
Current exec name is:schedule3
延时了1秒后执行,且执行了一次。
- 等待 delay 毫秒之后,首次执行,并且之后每隔 period 毫秒重复执行一次 task
public class MyTimer {
public static void main(String[] args) {
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()));
Timer timer = new Timer();
MyTimerTask myTimerTask = new MyTimerTask("schedule4");
timer.schedule(myTimerTask, 1000, 3000);
}
}
返回结果,
current exec time is:2019-07-30 16:01:36
current exec time is:2019-07-30 16:01:37
Current exec name is:schedule4
current exec time is:2019-07-30 16:01:40
Current exec name is:schedule4
current exec time is:2019-07-30 16:01:43
Current exec name is:schedule4
延迟一秒后第一次执行,之后每隔3秒执行一次。
scheduleAtFixedRate方法
- 时间等于或者超过 time 时首次执行 task,之后每隔 period 毫秒重复执行一次
public class MyTimer {
public static void main(String[] args) {
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()));
// 设置Calendar的时间比当前实际时间快3秒
calendar.add(Calendar.SECOND, 3);
Timer timer = new Timer();
MyTimerTask myTimerTask = new MyTimerTask("scheduleAtFixedRate1");
timer.scheduleAtFixedRate(myTimerTask, calendar.getTime(), 3000);
}
}
返回结果,
current exec time is:2019-07-30 16:11:48
current exec time is:2019-07-30 16:11:51
Current exec name is:scheduleAtFixedRate1
current exec time is:2019-07-30 16:11:54
Current exec name is:scheduleAtFixedRate1
current exec time is:2019-07-30 16:11:57
Current exec name is:scheduleAtFixedRate1
- 等待 delay 毫秒之后,首次执行,并且之后每隔 period 毫秒重复执行一次 task
public class MyTimer {
public static void main(String[] args) {
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()));
Timer timer = new Timer();
MyTimerTask myTimerTask = new MyTimerTask("scheduleAtFixedRate2");
timer.scheduleAtFixedRate(myTimerTask, 1000, 3000);
}
}
返回结果
current exec time is:2019-07-30 16:15:47
current exec time is:2019-07-30 16:15:48
Current exec name is:scheduleAtFixedRate2
current exec time is:2019-07-30 16:15:51
Current exec name is:scheduleAtFixedRate2
current exec time is:2019-07-30 16:15:54
Current exec name is:scheduleAtFixedRate2
两种方法差异对比
设定的首次执行时间早于当前时间
- schedule方法
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()));
// Calendar设置成比实际时间的6秒之前
calendar.add(Calendar.SECOND, -6);
System.out.println("current time minus six second is :"+ sf.format(calendar.getTime()));
System.out.println("Task is being executed!");
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("scheduled exec time is :"+ sf.format(scheduledExecutionTime()));
}
}, calendar.getTime(), 2000);
}
}
返回结果,
current time is:2019-07-31 13:09:57
current time minus six second is :2019-07-31 13:09:51
scheduled exec time is :2019-07-31 13:09:57
scheduled exec time is :2018-07-05 13:09:59
scheduled exec time is :2018-07-05 13:10:01
scheduled exec time is :2018-07-05 13:10:03
scheduled exec time is :2019-07-31 13:10:05
scheduled exec time is :2019-07-31 13:10:07
scheduled exec time is :2019-07-31 13:10:09
虽然将时间提前了6秒,但是使用 schedule方法还是从当前时间开始执行。然后每隔两秒执行一次。
- scheduleAtFixedRate方法
对上面的代码稍加修改,
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("scheduled exec time is :"+ sf.format(scheduledExecutionTime()));
}
}, calendar.getTime(), 2000);
返回结果,
current time is:2019-07-31 14:32:34
current time minus six second is :2019-07-31 14:32:28
scheduled exec time is :2019-07-31 14:32:28
scheduled exec time is :2019-07-31 14:32:30
scheduled exec time is :2019-07-31 14:32:32
scheduled exec time is :2019-07-31 14:32:34
scheduled exec time is :2019-07-31 14:32:36
scheduled exec time is :2019-07-31 14:32:38
在启动执行的时候,会立马执行3次,就是为了追赶已经过去的6秒。然后再按照设定的间隔,每两秒钟执行一次。
任务执行时间超出执行周期
假设任务执行需要3秒,而定义的执行的周期为2秒。
- schedule方法
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()));
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
// 模拟当前执行的过程需要 3秒
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("scheduled exec time is :"+ sf.format(scheduledExecutionTime()));
}
}, calendar.getTime(), 2000);
}
}
返回结果,
current time is:2019-07-31 14:43:51
scheduled exec time is :2019-07-31 14:43:51
scheduled exec time is :2019-07-31 14:43:54
scheduled exec time is :2019-07-31 14:43:57
scheduled exec time is :2019-07-31 14:44:00
scheduled exec time is :2019-07-31 14:44:03
当前的时间为 14:43:51,然后第一次计划执行的时间也为 14:43:51。但是以后每次执行的时间都是相隔 3秒钟,并不是我们上面设置 timerTask 的时间间隔 2秒。所以说使用 schedule 方法,在这种情况下会不断的延后。
- scheduleAtFixedRate方法
对上方代码进行修改,
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("scheduled exec time is :"+ sf.format(scheduledExecutionTime()));
}
}, calendar.getTime(), 2000);
}
返回结果,
current time is:2019-07-31 10:15:51
scheduled exec time is :2019-07-31 10:15:51
scheduled exec time is :2019-07-31 10:15:53
scheduled exec time is :2019-07-31 10:15:55
scheduled exec time is :2019-07-31 10:15:57
scheduled exec time is :2019-07-31 10:15:59
当执行的频率为2秒钟,但是执行的时间为3秒的时。从控制台上的输出可以看到,执行的频率还是为2秒,因此就会存在并发性。