java.util.Timer主要使用了Timer和TimerTask两个类。Timer内部有TimerThread和TaskQueue两个内部类,在创建Timer对象的时候会启动TimerThread线程,不断地从TaskQueue任务队列中取出头任务并执行,而Timer的各种schedule方法负责把TimerTask加入到队列中,使用了生产者消费者模型。
1.TimerTask
public abstract class TimerTask implements Runnable {
final Object lock = new Object(); // 锁
int state = VIRGIN; // VIRGIN、SCHEDULED、 EXECUTED、CANCELLED四种状态
long nextExecutionTime; // 执行时间
long period = 0;// 正值固定频率执行、负值固定延迟执行、0表示不重复执行
public abstract void run();
}
2.Timer
private final TaskQueue queue = new TaskQueue(); // 内部类,优先队列
private final TimerThread thread = new TimerThread(queue); // 内部类,用来执行任务的线程
private void sched(TimerTask task, long time, long period) {
if (time < 0)
throw new IllegalArgumentException("Illegal execution time.");
// 如果周期很大就把它变小点防止溢出
if (Math.abs(period) > (Long.MAX_VALUE >> 1))
period >>= 1;
synchronized(queue) {
if (!thread.newTasksMayBeScheduled)
throw new IllegalStateException("Timer already cancelled.");
synchronized(task.lock) {
if (task.state != TimerTask.VIRGIN)
throw new IllegalStateException(
"Task already scheduled or cancelled");
// 传入的时间作为下次执行时间,状态改为SCHEDULED
task.nextExecutionTime = time;
task.period = period;
task.state = TimerTask.SCHEDULED;
}
// 将任务加入队列中,如果该任务成为头任务,则唤醒队列。这包括两种情况:1、队列为空,唤醒等待的队列2、队列的头任务还没到执行时间进行wait,唤醒队列并重新进入mainloop循环
queue.add(task);
if (queue.getMin() == task)
queue.notify();
}
}
// 终止Timer。将执行线程的newTasksMayBeScheduled置为false,清空队列,并通知
public void cancel() {
synchronized(queue) {
thread.newTasksMayBeScheduled = false;
queue.clear();
queue.notify();
}
}
3.TimerThread
// class TimerThread extends Thread
// 主要方法是mainloop,死循环,每次从队列中取出任务进行执行
private void mainLoop() {
while (true) {
try {
TimerTask task;
boolean taskFired;
synchronized(queue) {
// 如果队列为空则等待
while (queue.isEmpty() && newTasksMayBeScheduled)
queue.wait();
if (queue.isEmpty())
break; // 走到这里说明Timer被终止了,执行线程跳出循环
// 队列非空取出头任务
long currentTime, executionTime;
task = queue.getMin();
synchronized(task.lock) {
// 如果任务状态是CANCELLED,从队列中移除该任务,重新进入循环
if (task.state == TimerTask.CANCELLED) {
queue.removeMin();
continue;
}
currentTime = System.currentTimeMillis();
executionTime = task.nextExecutionTime;
// 如果执行时间小于等于当前时间则taskFired为true,任务状态改为EXECUTED
if (taskFired = (executionTime<=currentTime)) {
if (task.period == 0) { // 不是重复执行的任务,进行移除
queue.removeMin();
task.state = TimerTask.EXECUTED;
} else { // 反复执行的任务,进行再调度。如果是固定延迟,下次执行时间为当前时间加上任务周期,如果是固定频率,下次执行时间为执行时间加上任务周期
queue.rescheduleMin(
task.period<0 ? currentTime - task.period
: executionTime + task.period);
}
}
}
// 如果下次执行时间大于当前时间,进行等待。要么等新任务加入并成为头任务唤醒,要么等够时间自己醒过来
if (!taskFired)
queue.wait(executionTime - currentTime);
}
// 执行任务
if (taskFired)
task.run();
} catch(InterruptedException e) {
}
}
}