这个定时执行任务的类是个单线程的,具体使用可以参考之前的文章。现在看看实现原理。
字段:
private final TaskQueue queue = new TaskQueue();
private final TimerThread thread = new TimerThread(queue);
定义了一个TaskQueue.以及一个TimerThread. 这个TaskQueue是一个TimerTask对象所构造的优先队列。TimerThread用于执行TaskQueue中的TimerTask.
构造函数:
public Timer() {
this("Timer-" + serialNumber());
}
public Timer(String name) {
thread.setName(name);
thread.start();
}
private final static AtomicInteger nextSerialNumber = new AtomicInteger(0);
private static int serialNumber() {
return nextSerialNumber.getAndIncrement();
}
构造函数做了如下几件事情:
1 定义了一个TimerThread线程对象的名称。
2 启动了TimerThread线程。
看看TimerThread对象的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
}
}
}
这里执行了一个mainLoop方法。
private void mainLoop() {
while (true) {
try {
TimerTask task;
boolean taskFired;
synchronized(queue) {
// Wait for queue to become non-empty
while (queue.isEmpty() && newTasksMayBeScheduled)
queue.wait();
if (queue.isEmpty())
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) {
}
}
}
在构造函数启动TimerThread线程后,进入这个while循环,锁定了queue队列,在这里判断队列是否为空,如果为空,则Timer主线程一直等待。
当运行了Timer的schedule方法后,这个方法如下:
public void schedule(TimerTask task, long delay) {
if (delay < 0)
throw new IllegalArgumentException("Negative delay.");
sched(task, System.currentTimeMillis()+delay, 0);
}
private void sched(TimerTask task, long time, long period) {
if (time < 0)
throw new IllegalArgumentException("Illegal execution time.");
// Constrain value of period sufficiently to prevent numeric
// overflow while still being effectively infinitely large.
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");
task.nextExecutionTime = time;
task.period = period;
task.state = TimerTask.SCHEDULED;
}
queue.add(task);
if (queue.getMin() == task)
queue.notify();
}
}
这里锁定了当前task对象并设置执行时间,状态,周期等,然后将这个task添加进queue。如果这个task在队列的第一个元素上,则唤醒队列进行执行。这里主线程会进入在wait方法后继续执行。
这里继续看主线程的执行:
锁定这个task对象并且判断状态。如果这个task没有被cancelled掉,那么会取得当前时间和task的执行时间,如果当前时间大于task的执行时间且task周期为0,则从队列中删除这个task,并且设置状态为已执行,否则这里重新schedule这个task。如果task没有到执行的时间,则queue等待。否则直接调用task的run方法。
从这里来看,Timer是单线程来执行queue的,因此有明显缺憾就是:
queue是按照顺序来执行,如果前面的task没执行完,后面的就要延期了。
如果前面的task抛异常导致timer线程停止,那么后面的task也不会被执行了。