1. 程式人生 > >java關於Timer schedule執行定時任務-轉

java關於Timer schedule執行定時任務-轉

java關於Timer schedule執行定時任務

1、在應用開發中,經常需要一些週期性的操作,比如每5分鐘執行某一操作等。對於這樣的操作最方便、高效的實現方式就是使用java.util.Timer工具類。

private java.util.Timer timer; 
timer = new Timer(true); 
timer.schedule(
new java.util.TimerTask() { public void run() { //server.checkNewMail(); 要操作的方法 } }, 0, 5*60*1000); 
      第一個引數是要操作的方法,第二個引數是要設定延遲的時間,第三個引數是週期的設定,每隔多長時間執行該操作。

    使用這幾行程式碼之後,Timer本身會每隔5分鐘呼叫一遍server.checkNewMail()方法,不需要自己啟動執行緒。Timer本身也是多執行緒同步的,多個執行緒可以共用一個Timer,不需要外部的同步程式碼。

 

2、
(1)Timer.schedule(TimerTask task,Date time)安排在制定的時間執行指定的任務。
(2)Timer.schedule(TimerTask task,Date firstTime ,long period)安排指定的任務在指定的時間開始進行重複的固定延遲執行.
(3)Timer.schedule(TimerTask task,long delay)安排在指定延遲後執行指定的任務.
(4)Timer.schedule(TimerTask task,long delay,long period)安排指定的任務從指定的延遲後開始進行重複的固定延遲執行.
(5)Timer.scheduleAtFixedRate(TimerTask task,Date firstTime,long period)安排指定的任務在指定的時間開始進行重複的固定速率執行.
(6)Timer.scheduleAtFixedRate(TimerTask task,long delay,long period)安排指定的任務在指定的延遲後開始進行重複的固定速率執行.

 

 

java timer 定時器

以下內容根據 The JavaTM Tutorial 和相關API doc翻譯整理,以供日後參考:
1.概覽
Timer是一種定時器工具,用來在一個後臺執行緒計劃執行指定任務。它可以計劃執行一個任務一次或反覆多次。
TimerTask一個抽象類,它的子類代表一個可以被Timer計劃的任務。

簡單的一個例程:

 

import java.util.Timer;
import java.util.TimerTask;

/**
* Simple demo that uses java.util.Timer to schedule a task to execute

* once 5 seconds have passed.
*/

public class Reminder {
    Timer timer;

    public Reminder(int seconds) {
        timer = new Timer();
        timer.schedule(new RemindTask(), seconds*1000);
    }

    class RemindTask extends TimerTask {
        public void run() {
            System.out.println("Time's up!");
            timer.cancel(); //Terminate the timer thread
        }
    }

    public static void main(String args[]) {
        System.out.println("About to schedule task.");
        new Reminder(5);
        System.out.println("Task scheduled.");
    }
}





執行這個小例子,你會首先看到:

About to schedule task.

5秒鐘之後你會看到:

Time's up!

這個小例子可以說明一些用Timer執行緒實現和計劃執行一個任務的基礎步驟:

實現自定義的TimerTask的子類,run方法包含要執行的任務程式碼,在這個例子裡,這個子類就是RemindTask。
例項化Timer類,建立計時器後臺執行緒。
例項化任務物件 (new RemindTask()). 
制定執行計劃。這裡用schedule方法,第一個引數是TimerTask物件,第二個引數表示開始執行前的延時時間(單位是milliseconds,這裡定義了5000)。還有一種方法可以指定任務的執行時間,如下例,指定任務在11:01 p.m.執行:
 //Get the Date corresponding to 11:01:00 pm today.
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, 23);
calendar.set(Calendar.MINUTE, 1);
calendar.set(Calendar.SECOND, 0);
Date time = calendar.getTime();

timer = new Timer();
timer.schedule(new RemindTask(), time); 

2.終止Timer執行緒
預設情況下,只要一個程式的timer執行緒在執行,那麼這個程式就會保持執行。當然,你可以通過以下四種方法終止一個timer執行緒:


呼叫timer的cancle方法。你可以從程式的任何地方呼叫此方法,甚至在一個timer task的run方法裡。
讓timer執行緒成為一個daemon執行緒(可以在建立timer時使用new Timer(true)達到這個目地),這樣當程式只有daemon執行緒的時候,它就會自動終止執行。 
當timer相關的所有task執行完畢以後,刪除所有此timer物件的引用(置成null),這樣timer執行緒也會終止。 
呼叫System.exit方法,使整個程式(所有執行緒)終止。 
Reminder 的例子使用了第一種方式。在這裡不能使用第二種方式,因為這裡需要程式保持執行直到timer的任務執行完成,如果設成daemon,那麼當main執行緒 結束的時候,程式只剩下timer這個daemon執行緒,於是程式不會等timer執行緒執行task就終止了。

有些時候,程式的終止與 否 並不只與timer執行緒有關。舉個例子,如果我們使用AWT來beep,那麼AWT會自動建立一個非daemon執行緒來保持程式的執行。下面的程式碼我們對 Reminder做了修改,加入了beeping功能,於是我們需要加入System.exit的呼叫來終止程式。
 

import java.util.Timer;
import java.util.TimerTask;
import java.awt.Toolkit;

/**
* Simple demo that uses java.util.Timer to schedule a task to execute
* once 5 seconds have passed.
*/

public class ReminderBeep {
    Toolkit toolkit;
    Timer timer;

    public ReminderBeep(int seconds) {
        toolkit = Toolkit.getDefaultToolkit();
        timer = new Timer();
        timer.schedule(new RemindTask(), seconds*1000);
    }

    class RemindTask extends TimerTask {
        public void run() {
            System.out.println("Time's up!");
    toolkit.beep();
    //timer.cancel(); //Not necessary because we call System.exit
    System.exit(0);   //Stops the AWT thread (and everything else)
        }
    }

    public static void main(String args[]) {
System.out.println("About to schedule task.");
        new ReminderBeep(5);
System.out.println("Task scheduled.");
    }
}



3.反覆執行一個任務

先看一個例子:
 

public class AnnoyingBeep {
    Toolkit toolkit;
    Timer timer;

    public AnnoyingBeep() {
        toolkit = Toolkit.getDefaultToolkit();
        timer = new Timer();
        timer.schedule(new RemindTask(),
               0,        //initial delay
               1*1000);  //subsequent rate
    }

    class RemindTask extends TimerTask {
        int numWarningBeeps = 3;

        public void run() {
            if (numWarningBeeps > 0) {
                toolkit.beep();
                System.out.println("Beep!");
                numWarningBeeps--;
            } else {
                toolkit.beep(); 
                System.out.println("Time's up!");
                //timer.cancel(); //Not necessary because we call System.exit
                System.exit(0);   //Stops the AWT thread (and everything else)
            }
        }
    }
    ...
}



執行,你會看到如下輸出:

Task scheduled.
Beep!      
Beep!      //one second after the first beep
Beep!      //one second after the second beep
Time's up! //one second after the third beep

這裡使用了三個引數的schedule方法用來指定task每隔一秒執行一次。如下所列為所有Timer類用來制定計劃反覆執行task的方法 : 
schedule(TimerTask task, long delay, long period) 
schedule(TimerTask task, Date time, long period) 
scheduleAtFixedRate(TimerTask task, long delay, long period) 
scheduleAtFixedRate(TimerTask task, Date firstTime, long period) 
當 計劃反覆執行的任務時,如果你注重任務執行的平滑度,那麼請使用schedule方法,如果你在乎的是任務的執行頻度那麼使用 scheduleAtFixedRate方法。 例如,這裡使用了schedule方法,這就意味著所有beep之間的時間間隔至少為1秒,也就是說,如 果有一個beap因為某種原因遲到了(未按計劃執行),那麼餘下的所有beep都要延時執行。如果我們想讓這個程式正好在3秒以後終止,無論哪一個 beep因為什麼原因被延時,那麼我們需要使用scheduleAtFixedRate方法,這樣當第一個beep遲到時,那麼後面的beep就會以最快 的速度緊密執行(最大限度的壓縮間隔時間)。

4.進一步分析schedule和scheduleAtFixedRate


(1) 2個引數的schedule在制定任務計劃時, 如果指定的計劃執行時間scheduledExecutionTime<= systemCurrentTime,則task會被立即執行。scheduledExecutionTime不會因為某一個task的過度執行而改變。
(2) 3個引數的schedule在制定反覆執行一個task的計劃時,每一次執行這個task的計劃執行時間隨著前一次的實際執行時間而變,也就是 scheduledExecutionTime(第n+1次)=realExecutionTime(第n次)+periodTime。也就是說如果第n 次執行task時,由於某種原因這次執行時間過長,執行完後的systemCurrentTime>= scheduledExecutionTime(第n+1次),則此時不做時隔等待,立即執行第n+1次task,而接下來的第n+2次task的 scheduledExecutionTime(第n+2次)就隨著變成了realExecutionTime(第n+1次)+periodTime。說 白了,這個方法更注重保持間隔時間的穩定。
(3)3個引數的scheduleAtFixedRate在制定反覆執行一個task的計劃時,每一 次 執行這個task的計劃執行時間在最初就被定下來了,也就是scheduledExecutionTime(第n次)=firstExecuteTime +n*periodTime;如果第n次執行task時,由於某種原因這次執行時間過長,執行完後的systemCurrentTime>= scheduledExecutionTime(第n+1次),則此時不做period間隔等待,立即執行第n+1次task,而接下來的第n+2次的 task的scheduledExecutionTime(第n+2次)依然還是firstExecuteTime+(n+2)*periodTime這 在第一次執行task就定下來了。說白了,這個方法更注重保持執行頻率的穩定。