Timer是jdk1.3中自帶的定時(shí)任務(wù)框架系統(tǒng).一個(gè)調(diào)度定時(shí)任務(wù)的工具線程類.可以執(zhí)行一個(gè)只調(diào)度一次的任務(wù)也可以重復(fù)調(diào)度一個(gè)一定間隔時(shí)間的任務(wù).
一個(gè)Timer實(shí)例就是一個(gè)調(diào)度任務(wù)調(diào)度線程.當(dāng)任務(wù)隊(duì)列中的所有定時(shí)任務(wù)被執(zhí)行完畢,這個(gè)定時(shí)調(diào)度的線程就會自動(dòng)終止.如果你想讓這個(gè)線程快速終止的話, 那么你可以直接調(diào)用cancel()方法可以讓調(diào)度線程快速終止.
Timer類是線程安全類:多個(gè)線程可以共享一個(gè)Timer實(shí)例.同時(shí)這個(gè)類不保證準(zhǔn)時(shí)調(diào)度任務(wù),因?yàn)樗怯玫腛bject.wait(long)方法.
Timer類能夠支持大量的并行調(diào)度任務(wù)(成百上千沒問題),在Timer內(nèi)部存儲每個(gè)調(diào)度任務(wù)的結(jié)構(gòu)是以平衡二叉樹堆(堆排序)的結(jié)構(gòu)來保存每個(gè)任務(wù)對象的,這種存儲結(jié)構(gòu)能在log(n)的時(shí)間復(fù)雜度內(nèi)快速的查詢.
jdk1.5中提供了比Timer跟高效的定時(shí)調(diào)度線程池類ScheduledThreadPoolExecutor
類定義
public class Timer {}
成員變量
修飾符 | 變量名 | 作用 |
---|---|---|
private final TaskQueue | queue = new TaskQueue() | 任務(wù)隊(duì)列 |
private final TimerThread | thread = new TimerThread(queue) | 定時(shí)調(diào)度任務(wù)的線程類 |
private final Object | threadReaper | 用于終止定時(shí)調(diào)度線程的 |
private final static AtomicInteger | nextSerialNumber = new AtomicInteger(0) | 用于生成定時(shí)調(diào)度線程的名字 |
構(gòu)造方法
當(dāng)我們實(shí)例化一個(gè)Timer類之后, 定時(shí)調(diào)度的線程就會啟動(dòng)start()一直等待(queue.wait())任務(wù)隊(duì)列中加入任務(wù)
public Timer() {
this("Timer-" + serialNumber());
}
public Timer(boolean isDaemon) {
this("Timer-" + serialNumber(), isDaemon);
}
public Timer(String name) {
thread.setName(name);
thread.start();
}
public Timer(String name, boolean isDaemon) {
thread.setName(name);
thread.setDaemon(isDaemon);
thread.start();
}
核心方法
Timer中有多個(gè)重載的public void schedule()方法,但是這些重載的方法只會做一些參數(shù)的判斷,并都最終調(diào)度的sched()方法,所以下面將講解sched()方法.
sched()方法
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;
// 獲取任務(wù)隊(duì)列的鎖(同一個(gè)線程多次獲取這個(gè)鎖并不會被阻塞,不同線程獲取時(shí)才可能被阻塞)
synchronized(queue) {
// 如果定時(shí)調(diào)度線程已經(jīng)終止了,則拋出異常結(jié)束
if (!thread.newTasksMayBeScheduled)
throw new IllegalStateException("Timer already cancelled.");
// 再獲取定時(shí)任務(wù)對象的鎖(為什么還要再加這個(gè)鎖呢?想不清)
synchronized(task.lock) {
// 判斷線程的狀態(tài),防止多線程同時(shí)調(diào)度到一個(gè)任務(wù)時(shí)多次被加入任務(wù)隊(duì)列
if (task.state != TimerTask.VIRGIN)
throw new IllegalStateException(
"Task already scheduled or cancelled");
// 初始化定時(shí)任務(wù)的下次執(zhí)行時(shí)間
task.nextExecutionTime = time;
// 重復(fù)執(zhí)行的間隔時(shí)間
task.period = period;
// 將定時(shí)任務(wù)的狀態(tài)由TimerTask.VIRGIN(一個(gè)定時(shí)任務(wù)的初始化狀態(tài))設(shè)置為TimerTask.SCHEDULED
task.state = TimerTask.SCHEDULED;
}
// 將任務(wù)加入任務(wù)隊(duì)列
queue.add(task);
// 如果當(dāng)前加入的任務(wù)是需要第一個(gè)被執(zhí)行的(也就是他的下一次執(zhí)行時(shí)間離現(xiàn)在最近)
// 則喚醒等待queue的線程(對應(yīng)到上面提到的queue.wait())
if (queue.getMin() == task)
queue.notify();
}
}
cancel()終止定時(shí)線程
public void cancel() {
// 從這里可以知道,如果調(diào)用了Timer的cancel()方法也不會立刻就終止定時(shí)調(diào)度線程
// 因?yàn)檫@里需要獲取任務(wù)隊(duì)列的鎖,如果TimerThread占用了queue的鎖,也就是說queue并沒有在wait(),
// 那么cancel就不會立刻終止定時(shí)線程, 他需要等待TimerThread定時(shí)線程釋放掉queue的鎖
// 也就是說如果queue隊(duì)列中有定時(shí)任務(wù)存在,那么cancel就不會終止定時(shí)線程,他需要等到queue中的定時(shí)任務(wù)被清空
// 用一句話說: cancel會等到所有定時(shí)任務(wù)執(zhí)行完后立刻終止定時(shí)線程
synchronized(queue) {
thread.newTasksMayBeScheduled = false;
queue.clear();
queue.notify(); // In case queue was already empty.
}
}
purge()方法
從隊(duì)列中移除所有狀態(tài)為cancelled的任務(wù),調(diào)用這個(gè)方法并不會影響timer的行為,但是一般應(yīng)用不會調(diào)用這個(gè)方法,除非有很多被cancelled的任務(wù);同時(shí)調(diào)用這個(gè)方法也會比較消耗時(shí)間.
TimerThread類
TimerThread是Timer中定時(shí)調(diào)度線程類的定義,這個(gè)類會做為一個(gè)線程一直運(yùn)行來執(zhí)行Timer中任務(wù)隊(duì)列中的任務(wù).
類定義
class TimerThread extends Thread
成員變量
修飾符 | 變量名 | 作用 |
---|---|---|
boolean | newTasksMayBeScheduled = true | 用于控制當(dāng)queue任務(wù)隊(duì)列為空時(shí),定時(shí)線程是否應(yīng)該立刻終止(false立刻終止) |
private TaskQueue | queue | 任務(wù)隊(duì)列(這個(gè)當(dāng)TimerThread在Timer中被實(shí)例化時(shí)會傳入) |
方法
run()方法
定時(shí)線程的執(zhí)行方法,它會調(diào)用TimerThread類的mainLoop()方法.
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() {
// 無限循環(huán)來控制等待任務(wù)隊(duì)列中加入任務(wù)
while (true) {
try {
TimerTask task;
boolean taskFired;
// 獲取任務(wù)隊(duì)列的鎖
synchronized(queue) {
// 如果任務(wù)隊(duì)列為空,并且線程沒有被cancel()
// 則線程等待queue鎖,queue.wait()方法會釋放獲得的queue鎖
// 這樣在Timer中sched()方法才能夠獲取到queue鎖
while (queue.isEmpty() && newTasksMayBeScheduled)
queue.wait();
// 如果任務(wù)隊(duì)列為空了,那么就退出循環(huán)
// 這種情況要發(fā)生,那么必須newTasksMayBeScheduled=false
// 因?yàn)槿绻鹡ewTasksMayBeScheduled=true,就會在上面的while循環(huán)中執(zhí)行queue.wait(),使線程進(jìn)入等待狀態(tài)
// 等線程從等待狀態(tài)恢復(fù)時(shí),說明queue.notify()方法被調(diào)用了,
// 而觀察Timer代碼這只可能在sched()方法中發(fā)生, 這個(gè)方法會在隊(duì)列queue中add任務(wù)而使queue不再為空
if (queue.isEmpty())
break;
long currentTime, executionTime;
// 得到任務(wù)隊(duì)列中的位置1的任務(wù)
task = queue.getMin();
// 獲取任務(wù)的鎖
synchronized(task.lock) {
// 如果任務(wù)被取消了(TimerTask.cancel()方法被調(diào)用)
// 將任務(wù)從隊(duì)列中移除,繼續(xù)重新循環(huán)
if (task.state == TimerTask.CANCELLED) {
queue.removeMin();
continue; // No action required, poll queue again
}
// 獲取任務(wù)的執(zhí)行時(shí)間
currentTime = System.currentTimeMillis();
executionTime = task.nextExecutionTime;
// 計(jì)算任務(wù)是否應(yīng)該被觸發(fā)
if (taskFired = (executionTime<=currentTime)) {
// 任務(wù)應(yīng)該被觸發(fā),并且不是重復(fù)任務(wù)
// 將任務(wù)從隊(duì)列中移除并修改任務(wù)的執(zhí)行狀態(tài)
if (task.period == 0) { // Non-repeating, remove
queue.removeMin();
task.state = TimerTask.EXECUTED;
} else { // 任務(wù)是重復(fù)執(zhí)行任務(wù),計(jì)算任務(wù)下一次應(yīng)該被執(zhí)行的時(shí)間,并重新排序任務(wù)隊(duì)列
queue.rescheduleMin(
task.period<0 ? currentTime - task.period
: executionTime + task.period);
}
}
}
// 如果任務(wù)不應(yīng)被觸發(fā),讓其等待一定時(shí)間后執(zhí)行
if (!taskFired) // Task hasn't yet fired; wait
queue.wait(executionTime - currentTime);
}
// 任務(wù)應(yīng)該被觸發(fā),讓任務(wù)執(zhí)行
if (taskFired) // Task fired; run it, holding no locks
task.run(); // 任務(wù)也是一個(gè)線程
} catch(InterruptedException e) {
}
}
}
TaskQueue類
TaskQueue是一個(gè)任務(wù)隊(duì)列類,用于保存定時(shí)器需要執(zhí)行的定時(shí)任務(wù),這個(gè)隊(duì)列是一個(gè)數(shù)組,只不過是一種平衡二叉樹堆結(jié)構(gòu)的數(shù)組.至于這個(gè)樹堆是怎么樣一種結(jié)構(gòu),還請執(zhí)行百度.只能說這種結(jié)構(gòu)總是保證值最小或者是值最大的在數(shù)組中的第一個(gè)位置(這個(gè)類中始終是nextExecuteTime最小的在第一個(gè)位置),沒當(dāng)隊(duì)列有增加,刪除操作就會重新調(diào)整隊(duì)列結(jié)構(gòu),讓nextExecuteTime值最小的放在第一個(gè)位置.
TimerTask類
TimerTask任務(wù)類,繼承自Thread,如果我們要用Timer來做定時(shí)任務(wù),那么我們必須繼承TimerTask類,并且實(shí)現(xiàn)run()方法(具體任務(wù)代碼).如果要取消一個(gè)任務(wù)的調(diào)度,則調(diào)用TimerTask.cancel()方法將取消任務(wù)的執(zhí)行.