拾遺Timer定時器
一 Timer 介紹
在開發中我們經常會遇到一些簡單定時任務的需求,而不需要量級較重的定時任務就可以採取java定時器;
java.util.Timer工具類中的Timer 是定時器,但定時任務寫在java.util.TimerTask 中,由 Timer 執行 TimerTask ;
Timer 的本質就是執行緒,構造方法如下
public Timer(String name) {
thread.setName(name);
thread.start();
}
從原始碼角度可知,如果這樣建立定時器非守護執行緒,即使主執行緒執行結束,定時任務還是會執行;如果我們會使用如下的構造方式建立定時任務就是守護執行緒方式,會隨著主執行緒的消亡而消亡;
public Timer(String name, boolean isDaemon) {
thread.setName(name);
thread.setDaemon(isDaemon);
thread.start();
}
Timer內部維護了一個優先佇列,用於順序執行TimerTask任務;
private final TaskQueue queue = new TaskQueue();
private final TimerThread thread = new TimerThread(queue);
優先佇列的實現就是陣列方式作為平衡二叉堆
private TimerTask[] queue = new TimerTask[128];
TimerTask 實現了Runnable 介面,執行的任務動作就是run方法;
public abstract class TimerTask implements Runnable {
// ....
protected TimerTask() {
}
public abstract void run();
//....
}
所以定時器的本質就是啟動了一個新的執行緒執行任務,這些任務都會維護在優先佇列裡面;
timer的排程主要方法如下
- schedule(TimerTask task, long delay) 延遲 delay 毫秒執行一次
- schedule(TimerTask task, Date time) 指定時間執行一次
- schedule(TimerTask task, long delay, long period) 延遲delay毫秒以後,每隔period毫秒執行一次
- schedule(TimerTask task, Date firstTime, long period) 從firstTime時刻開始,每隔period毫秒執行一次
二 Timer使用示例
如果方式簡單使用Timer去延遲執行執行緒任務,當然其它四種方法同理,呼叫方式區別不大;
public static void main(String[] args) {
// 建立定時器
Timer timer = new Timer("知識追尋者");
// 建立定時器任務;實現run 方法
TimerTask timerTask = new TimerTask() {
@Override
public void run() {
System.out.println("執行緒執行了"+ LocalTime.now());
}
};
System.out.println("程式執行時間"+ LocalTime.now());
// 啟動定時器
timer.schedule(timerTask,5000);
}
輸出的間隔大約就是5秒
程式執行時間 18:47:28.258
執行緒執行了18:47:33.259
三 cancel 方法
TimerTask的cancel () 方法是將自身任務從任務佇列中移除
我們先延遲2秒,再每2秒執行一次看效果
public static void main(String[] args) {
// 建立定時器
Timer timer = new Timer("知識追尋者");
// 建立定時器任務;實現run 方法
TimerTask timerTask = new TimerTask() {
@Override
public void run() {
System.out.println("執行緒執行了"+ LocalTime.now());
}
};
System.out.println("程式執行時間"+ LocalTime.now());
// 啟動定時器
timer.schedule(timerTask,2000,2000);
}
結果是每2秒會執行一次
程式執行時間18:59:23.557
執行緒執行了18:59:25.558
執行緒執行了18:59:27.558
執行緒執行了18:59:29.559
啟用cancel方法,後 就只會執行一次
public static void main(String[] args) {
// 建立定時器
Timer timer = new Timer("知識追尋者");
// 建立定時器任務;實現run 方法
TimerTask timerTask = new TimerTask() {
@Override
public void run() {
System.out.println("執行緒執行了"+ LocalTime.now());
// 呼叫 cancel方法
this.cancel();
}
};
System.out.println("程式執行時間"+ LocalTime.now());
// 啟動定時器
timer.schedule(timerTask,2000,2000);
}
輸出如下
程式執行時間19:02:12.770
執行緒執行了19:02:14.772
Timer的cancel方法是移除所有的任務;
public static void main(String[] args) {
// 建立定時器
Timer timer = new Timer("知識追尋者");
// 建立定時器任務;實現run 方法
TimerTask timerTask = new TimerTask() {
@Override
public void run() {
System.out.println("執行緒執行了"+ LocalTime.now());
}
};
System.out.println("程式執行時間"+ LocalTime.now());
timer.cancel();
// 啟動定時器
timer.schedule(timerTask,2000,2000);
}
輸出直接報錯
程式執行時間:19:34.294
Exception in thread "main" java.lang.IllegalStateException: Timer already cancelled.
at java.util.Timer.sched(Timer.java:397)
at java.util.Timer.schedule(Timer.java:248)
at com.youku1327.base.timer.TimerAbsolute.main(TimerAbsolute.java:28)
四 scheduleAtFixedRate
schedule 與 scheduleAtFixedRate 方法的區別如下:
schedule 方法如果執行任務的時間沒有被延遲,下一次執行任務時間參考的是上一次任務執行的開始時間
scheduleAtFixedRate 方法如果執行任務的時間沒有被延遲,下一次執行任務時間參考的是上一次任務執行的結束時間
五 Timer缺點
- Timer 對排程的支援是基於絕對時間的,而不是相對時間,所以它對系統時間的改變非常敏感。
- Timer 執行緒是不會捕獲異常的,如果 TimerTask 丟擲的了未檢查異常則會導致 Timer 執行緒終止。
關注公眾號:回覆 拍拍知識追尋者,領取面試資料和原創PDF教程;