java.util.Timer计时器有管理任务延迟执行("如1000ms后执行任务")以及周期性执行("如每500ms执行一次该任务")。但是,Timer存在一些缺陷,因此你应该考虑使用ScheduledThreadPoolExecutor作为代替品,Timer对调度的支持是基于绝对时间,而不是相对时间的,由此任务对系统时钟的改变是敏感的;ScheduledThreadExecutor只支持相对时间。
Timer的另一个问题在于,如果TimerTask抛出未检查的异常,Timer将会产生无法预料的行为。Timer线程并不捕获异常,所以TimerTask抛出的未检查的异常会终止timer线程。这种情况下,Timer也不会再重新恢复线程的执行了;它错误的认为整个Timer都被取消了。此时,已经被安排但尚未执行的TimerTask永远不会再执行了,新的任务也不能被调度了。
public class OutOfTime {
public static void main(String[] args) throws Exception {
Timer timer = new Timer();
timer.schedule(new ThrowTask(), 1);
SECONDS.sleep(1);
timer.schedule(new ThrowTask(), 1);
SECONDS.sleep(5);
} static class ThrowTask extends TimerTask {
public void run() {
/*try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}*/
throw new RuntimeException();
}
}
}
执行结果
Exception in thread "Timer-0" java.lang.RuntimeException
at net.jcip.examples.OutOfTime$ThrowTask.run(OutOfTime.java:31)
at java.util.TimerThread.mainLoop(Timer.java:555)
at java.util.TimerThread.run(Timer.java:505)
Exception in thread "main" java.lang.IllegalStateException: Timer already cancelled.
at java.util.Timer.sched(Timer.java:397)
at java.util.Timer.schedule(Timer.java:193)
at net.jcip.examples.OutOfTime.main(OutOfTime.java:19)
Timer单线程执行任务,任务有可能丢失或执行时间不准确。
Timer执行任务时只是创建了单个线程。如果一个时间任务执行的时间比较长,那么其他任务执行时间的准确性就会受影响。比如每隔1秒执行一次任务,中间有个长任务执行时间超过5秒,那么在上一个任务执行完成时,会快速执行4次或者丢失任务。
public class OutOfTime {
public static void main(String[] args) throws Exception {
Timer timer = new Timer();
timer.schedule(new ThrowTask(), 1);
SECONDS.sleep(1);
timer.schedule(new ThrowTask(), 1);
SECONDS.sleep(5);
} static class ThrowTask extends TimerTask {
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
throw new RuntimeException();
}
}
}
执行结果
Exception in thread "Timer-0" java.lang.RuntimeException
at net.jcip.examples.OutOfTime$ThrowTask.run(OutOfTime.java:31)
at java.util.TimerThread.mainLoop(Timer.java:555)
at java.util.TimerThread.run(Timer.java:505)