這個定時執行任務的類是個單線程的,具體使用可以參考之前的文章。現在看看實作原理。
字段:
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();
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 == ) { // Non-repeating, remove
queue.removeMin();
task.state = TimerTask.EXECUTED;
} else { // Repeating task, reschedule
queue.rescheduleMin(
task.period< ? 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 < )
throw new IllegalArgumentException("Negative delay.");
sched(task, System.currentTimeMillis()+delay, );
}
private void sched(TimerTask task, long time, long period) {
if (time < )
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 >> ))
period >>= ;
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也不會被執行了。