先來看下timer的調用方式,簡單的定時打印java
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); }
運行結果:node
Timer-0
Timer-0
Timer-0
Timer-0
Timer-0多線程
而後我好奇它是如何實現定時調用的,打開TimerTask類的源碼,發現它是一個對runable的封裝,添加了一些狀態和同步鎖對象以及下次執行的時間,它封裝瞭如下狀態ide
/**
* This task has not yet been scheduled.任務尚未被調用
*/
static final int VIRGIN = 0;oop
/**
* This task is scheduled for execution. If it is a non-repeating task,
* it has not yet been executed. 任務被調度去執行,若是是一個不循環執行的任務,表示它尚未被執行
*/
static final int SCHEDULED = 1;ui
/**
* This non-repeating task has already executed (or is currently
* executing) and has not been cancelled.不重複執行任務已經執行或者正在執行,不能被取消
*/
static final int EXECUTED = 2;this
/**
* This task has been cancelled (with a call to TimerTask.cancel).任務已經被取消,(調用 timerTask 的cancel 方法
*/
static final int CANCELLED = 3;線程
/**code
* 下次執行的時間,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;orm
/**
* 執行間隔
* 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的方式實現的定時任務,因爲實現方式的侷限性,致使不能支持更多的特性,多線程,天然時間等。