先来看下timer的调用方式,简单的定时打印
public static void main(String[] args){
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
}, 5000, 5000);
}
运行结果:
Timer-0
Timer-0
Timer-0
Timer-0
Timer-0
然后我好奇它是如何实现定时调用的,打开TimerTask类的源码,发现它是一个对runable的封装,添加了一些状态和同步锁对象以及下次执行的时间,它封装了以下状态
/**
* This task has not yet been scheduled.任务还没有被调用
*/
static final int VIRGIN = 0;
/**
* This task is scheduled for execution. If it is a non-repeating task,
* it has not yet been executed. 任务被调度去执行,如果是一个不循环执行的任务,表示它还没有被执行
*/
static final int SCHEDULED = 1;
/**
* This non-repeating task has already executed (or is currently
* executing) and has not been cancelled.不重复执行任务已经执行或者正在执行,不能被取消
*/
static final int EXECUTED = 2;
/**
* This task has been cancelled (with a call to TimerTask.cancel).任务已经被取消,(调用 timerTask 的cancel 方法
*/
static final int CANCELLED = 3;
/**
* 下次执行的时间,System.currentTimeMillis 格式
* Next execution time for this task in the format returned by
* System.currentTimeMillis, assuming this task is scheduled for execution.
* For repeating tasks, this field is updated prior to each task execution.
*/
long nextExecutionTime;
/**
* 执行间隔
* Period in milliseconds for repeating tasks. A positive value indicates
* fixed-rate execution. A negative value indicates fixed-delay execution.
* A value of 0 indicates a non-repeating task.
*/
long period = 0;
以上可以看出timer+timerTask的方式不适合使用自然时间的任务。
Timer.class
timer主要有两个关键的成员变量final修饰
//内部类实现,timerTask的队列,封装实现了,最大128个任务
private final TaskQueue queue = new TaskQueue();
/**
* The timer thread.,内部类,一个线程的封装实现
*/
private final TimerThread thread = new TimerThread(queue);
先简单介绍下TaskQueue.class,看成员变量
/**
保存定时任务队列,可以看到最大一个timer最多可以提交128个任务
* Priority queue represented as a balanced binary heap: the two children
* of queue[n] are queue[2*n] and queue[2*n+1]. The priority queue is
* ordered on the nextExecutionTime field: The TimerTask with the lowest
* nextExecutionTime is in queue[1] (assuming the queue is nonempty). For
* each node n in the heap, and each descendant of n, d,
* n.nextExecutionTime <= d.nextExecutionTime.
*/
private TimerTask[] queue = new TimerTask[128];
/**
* The number of tasks in the priority queue. (The tasks are stored in
* queue[1] up to queue[size]).
*/
private int size = 0;
TaskQueue提供了一系列方法是对该队列即将执行的任务的操作,获取最近要执行的人,修改任务的下次执行时间
主要是有两个私有方法fixUp(),fixDown();用来更新队列的顺序。
再来看下TimerThread.class,主要看下run方法
public void run() {
try {
mainLoop();
} finally {
// Someone killed this Thread, behave as if Timer cancelled
//遇到异常或取消任务,清空任务队列,修改状态,不按照可以提交新的任务
synchronized(queue) {
newTasksMayBeScheduled = false;
queue.clear(); // Eliminate obsolete references
}
}
}
/**
* The main timer loop. (See class comment.)
*/
private void mainLoop() {
//使用while(true)实现线程一直在运行,而不是任务到时间了另起一个线程,所以timer只有一个线程
while (true) {
try {
TimerTask task;
boolean taskFired;
synchronized(queue) {
// Wait for queue to become non-empty
while (queue.isEmpty() && newTasksMayBeScheduled)
//new timer()的时候线程已经启动了的,在这里等带任务的提交,为什么是用while呢?
queue.wait();
if (queue.isEmpty())//队列空直接退出,在停止timer的情况下
break; // Queue is empty and will forever remain; die
// Queue nonempty; look at first evt and do the right thing
long currentTime, executionTime;
task = queue.getMin();//获取最近要执行
synchronized(task.lock) {
if (task.state == TimerTask.CANCELLED) {//取消状态的任务,从队列中删除,并不往下执行
queue.removeMin();
continue; // No action required, poll queue again
}
currentTime = System.currentTimeMillis();
executionTime = task.nextExecutionTime;
if (taskFired = (executionTime<=currentTime)) {
//如果任务下次执行时间小于等于当前时间,即该任务可以执行
if (task.period == 0) { // Non-repeating, remove
queue.removeMin();//非循环任务,从队列中删除,并修改任务状态
task.state = TimerTask.EXECUTED;
} else { // Repeating task, reschedule
//循环任务,需要重新构建队列排序
queue.rescheduleMin(
task.period<0 ? currentTime - task.period
: executionTime + task.period);
}
}
}
if (!taskFired) // Task hasn't yet fired; wait//最近的任务还没到时间,在等待
queue.wait(executionTime - currentTime);
}
if (taskFired) // Task fired; run it, holding no locks
task.run();//执行任务
} catch(InterruptedException e) {
}
}
}
}
可以看到timer的定时其实是使用一个线程while(true)和,wait(),notify()配合实现的。代码有注释不多解释了。
总结:
jdk timer + timertask的方式实现的定时任务,由于实现方式的局限性,导致不能支持更多的特性,多线程,自然时间等。