Timer和TimerTask詳解

一、概述java

Timer是一種定時器工具,用來在一個後臺線程計劃執行指定任務。它能夠計劃執行一個任務一次或反覆屢次。安全

TimerTask是一個抽象類,它的子類表明一個能夠被Timer計劃的任務。工具

簡單的一個例子程序:spa

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.code

5秒鐘以後你會看到:對象

Time's up!get

這個小例子能夠說明一些用Timer線程實現和計劃一個任務的基礎步驟:
it

一、實現自定義的TimerTask的子類,run方法包含要執行的任務代碼,在這個例子裏,這個子類就是RemindTask。io

二、實例化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);

二、終止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就定下來了。說白了,這個方法更注重保持執行頻率的穩定。

5.一些注意的問題

每個Timer僅對應惟一一個線程。

Timer不保證任務執行的十分精確。

Timer類的線程安全的。

相關文章
相關標籤/搜索