Timer是jdk中提供的一个定时器工具,每个Timer都会启动一个线程,用于顺序地执行所有计时器任务,可安排任务执行一次,或者定期重复执行。
TimerTask是一个实现了Runnable接口的抽象类,代表一个可以被Timer执行的任务。
每一个Timer仅对应唯一一个线程。
Timer不保证任务执行的十分精确。
Timer类的线程安全的。
Timer():创建一个新计时器,其相关的线程不 作为守护程序运行。
Timer(String name):创建一个新计时器,其相关的线程具有指定的名称,相关的线程不 作为守护程序运行。
Timer(booleanisDaemon):如果应该将相关的线程作为守护程序运行,则为 true。
Timer(Stringname, booleanisDaemon):name
- 相关线程的名称。isDaemon
- 如果应该将相关的线程作为守护程序运行,则为 true。
取消此计时器任务。
如果任务安排为一次执行且还未运行,或者尚未安排,则永远不会运行。
如果任务安排为重复执行,则永远不会再运行。
如果发生此调用时任务正在运行,则任务将运行完,但永远不会再运行。
注意,从重复的计时器任务的 run 方法中调用此方法绝对保证计时器任务不会再运行。
此方法可以反复调用;第二次和以后的调用无效。
返回:
如果此任务安排为一次执行且尚未运行,或者此任务安排为重复执行,则返回 true。
如果此任务安排为一次执行且已经运行,或者此任务尚未安排,或者此任务已经取消,则返回 false。
此计时器任务要执行的操作。需要我们重写。
返回此任务最近实际 的已安排 执行时间,可以理解为计划执行的时间。是毫秒值,值可以参考java.util.Date的gettime()方法的返回值。
使用Timer类的cancel()方法:终止此计时器,丢弃所有当前已安排的任务。这不会干扰当前正在执行的任务(如果存在)。一旦终止了计时器,那么它的执行线程也会终止,并且无法根据它安排更多的任务。
scheduleAtFixedRate与schedule方法的侧重点不同,schedule方法侧重保存间隔时间的稳定,而scheduleAtFixedRate方法更加侧重于保持执行频率的稳定。
在schedule方法中会因为前一个任务的延迟而导致其后面的定时任务延时,因此后一个任务的计划执行时间会根据前一个任务的执行时间加上任务延时时间。而scheduleAtFixedRate方法则不会,如果第n个任务执行时间过长导致当前系统时间>= 第n+1个任务的计划执行时间,则不会做任何等待他会立即执行第n+1个任务。
所以scheduleAtFixedRate方法计划执行时间的计算方法不同于schedule,而是scheduledExecutionTime(n)=firstExecuteTime +n*periodTime,该计算方法永远保持不变。所以scheduleAtFixedRate更加侧重于保持执行频率的稳定。
public static void main(String[] args) {
final Timer timer = new Timer();
TimerTask tt = new TimerTask() {
@Override
public void run() {
System.out.println("tt:"
+ new SimpleDateFormat("yyyy/MM/dd HH:mm:ss")
.format(new Date()));
timer.cancel();
}
};
timer.schedule(tt, 1000);
}
这里直接new一个TimerTask,我们也可以写个类继承TimerTask。1秒后执行任务,执行完成后调用cancel方法终止定时器。public static void main(String[] args) {
final Timer timer = new Timer();
TimerTask tt = new TimerTask() {
@Override
public void run() {
System.out.println("tt:"
+ new SimpleDateFormat("yyyy/MM/dd HH:mm:ss")
.format(new Date()));
}
};
timer.schedule(tt, 1000, 2000);
}
tt:2015/07/29 13:09:38
tt:2015/07/29 13:09:40
tt:2015/07/29 13:09:42
tt:2015/07/29 13:09:44
tt:2015/07/29 13:09:46
···
用法和上面的例子类似,只是把指定的延迟改为指定的时间。
public static void main(String[] args) {
final Timer timer = new Timer();
TimerTask tt = new TimerTask() {
@Override
public void run() {
System.out.println("tt:"
+ new SimpleDateFormat("yyyy/MM/dd HH:mm:ss")
.format(new Date()));
try {
// 睡眠3秒
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
timer.scheduleAtFixedRate(tt, 1000, 2000);
}
结果:由于每一个任务后睡眠了3秒,超过了循环执行的间隔时间,因此每次睡眠完就立马执行下一次任务,因此这里变成了3秒执行一次。
tt:2015/07/29 13:25:54
tt:2015/07/29 13:25:57
tt:2015/07/29 13:26:00
tt:2015/07/29 13:26:03
···
用法和上面的例子类似,只是把指定的延迟改为指定的时间。
Timer计时器可以定时(指定时间执行任务)、延迟(延迟5秒执行任务)、周期性地执行任务(每隔个1秒执行任务),但是,Timer存在一些缺陷。首先Timer对调度的支持是基于绝对时间的,而不是相对时间,所以它对系统时间的改变非常敏感。其次Timer线程是不会捕获异常的,如果TimerTask抛出的了未检查异常则会导致Timer线程终止,同时Timer也不会重新恢复线程的执行,他会错误的认为整个Timer线程都会取消。同时,已经被安排单尚未执行的TimerTask也不会再执行了,新的任务也不能被调度。故如果TimerTask抛出未检查的异常,Timer将会产生无法预料的行为。