java.util.Timer是从jdk1.3版本就存在的java原生定时器实现,现在做项目已经不推荐使用它来实现定时任务,为什么呢?让我们从源码上一探究竟。
原因分析
只有一个线程执行定时任务,一个Timer多个任务的情况下,不能保证任务按指定定时策略执行。
如果前一个定时任务执行太久,超过后一个定时任务的定时间隔,后一个任务会延时执行。
整个Timer采用“生产者—消费者”模式实现。TaskQueue queue存储定时任务,TimerThread thread执行定时任务。1
2
3
4
5
6
7
8
9
10
11
12/**
* The timer task queue. This data structure is shared with the timer
* thread. The timer produces tasks, via its various schedule calls,
* and the timer thread consumes, executing timer tasks as appropriate,
* and removing them from the queue when they're obsolete.
*/
private final TaskQueue queue = new TaskQueue();
/**
* The timer thread.
*/
private final TimerThread thread = new TimerThread(queue);TimerTask task.run() 不会开新线程,如果阻塞,后面的任务都会阻塞。
只有一个执行定时任务的线程,如果这个线程出现异常而终止,则整个定时任务就终止了,没有可靠性保证。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20TimerTask t1 = new TimerTask() {
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("t1 run");
int a = 1/0;
}
};
TimerTask t2 = new TimerTask() {
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("t2 run");
}
};
Timer timer = new Timer("Timer");
timer.scheduleAtFixedRate(t1, 2000, 1000);
timer.scheduleAtFixedRate(t2, 1000, 1000);程序输出:
t2 run
t2 run
t1 run
报除零错,定时线程异常结束,整个定时器结束。
结论
原生Timer已不适合在工程项目中使用,不过看看源码,学习下Java库开发者的思想及实现方法还是可取的。