1. 程式人生 > >JAVA隨筆篇一(Timer源代碼分析和scheduleAtFixedRate的使用)

JAVA隨筆篇一(Timer源代碼分析和scheduleAtFixedRate的使用)

exce 啟動 get stat dsm ldr 基礎篇 ask pty

寫完了基礎篇,想了非常久要不要去寫進階篇。去寫JSP等等的用法。最後決定先不去寫。由於自己並非JAVA方面的大牛。眼下也在邊做邊學,所以決定先將自己不懂的拿出來學並記下來。

Timer是Java自帶的java.util.Timer類,通過調度一個java.util.TimerTask任務。這樣的方式能夠讓程序依照某一個頻度運行。


1、Timer類的源代碼分析:

public class Timer {
    /**
     * The timer task queue.  This data structure is shared with the timer
     * thread.  The timer produces tasks, via its various schedule calls,
     * and the timer thread consumes, executing timer tasks as appropriate,
     * and removing them from the queue when they‘re obsolete.
     */
    private TaskQueue queue = new TaskQueue();

    /**
     * The timer thread.
     */
    private TimerThread thread = new TimerThread(queue);
首先Timer類定義了兩個私有變量TaskQueue和TimerThread。


TaskQueue:Timer類定義了一個定時器任務隊列。一個TimerTasks的優先級隊列。

class TaskQueue {
    /**
     * 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];

TimerThread:Timer類的任務運行線程。從Thread類繼承。以TaskQueue為參數。


在使用Timer類,首先new一個Timer對象,然後利用scheduleXXX函數運行任務,首先分析Timer對象構造過程:

    public Timer() {
        this("Timer-" + serialNumber());
    }
    public Timer(boolean isDaemon) {
        this("Timer-" + serialNumber(), isDaemon);
    }<span style="white-space:pre">	</span>
    public Timer(String name) {
        thread.setName(name);
        thread.start();
    }
    public Timer(String name, boolean isDaemon) {
        thread.setName(name);
        thread.setDaemon(isDaemon);
        thread.start();
    }
能夠看出,Timer在構造對象過程中,須要啟動一個TimerThread線程,因此能夠推測,TimerThread線程和Timer對象共同維護一個TaskQueue,利用TaskQueue進行信息傳遞。

接下來看scheduleXXX函數。全部的scheduleXXX函數都須要調用sched方法,

private void sched(TimerTask task, long time, long period) {
        if (time < 0)
            throw new IllegalArgumentException("Illegal execution time.");

        synchronized(queue) {
            if (!thread.newTasksMayBeScheduled)
                throw new IllegalStateException("Timer already cancelled.");

            synchronized(task.lock) {
                if (task.state != TimerTask.VIRGIN)
                    throw new IllegalStateException(
                        "Task already scheduled or cancelled");
                task.nextExecutionTime = time;
                task.period = period;
                task.state = TimerTask.SCHEDULED;
            }

            queue.add(task);
            if (queue.getMin() == task)
                queue.notify();
        }
    }
這裏首先介紹一下TimerTask類:

public abstract class TimerTask implements Runnable {
    /**
     * This object is used to control access to the TimerTask internals.
     */
    final Object lock = new Object();

TimerTask類實現了Runnable接口,待運行的任務置於run()中。在構造定時任務的時候。從TimerTask繼承並實現run方法。並創建任務傳給scheduleXXX方法。

sched方法中能夠看出,sched方法中須要操作TaskQueue隊列,而TimerThread線程啟動之後相同使用這個隊列,這就必須使用synchronized保證多線程安全使用。

2、scheduleXXX的使用:

Timer類的原理非常easy,能夠使用的函數不多。以下將所有列出。

(1)void java.util.Timer.schedule(TimerTask task, long delay):多長時間(毫秒)後運行任務

(2)void java.util.Timer.schedule(TimerTask task, Date time):設定某個時間運行任務

(3)void java.util.Timer.schedule(TimerTask task, long delay, long period):delay時間後開始運行任務,並每隔period時間調用任務一次。

(4)void java.util.Timer.schedule(TimerTask task, Date firstTime, long period):第一次在指定firstTime時間點運行任務,之後每隔period時間調用任務一次。

(5)void java.util.Timer.scheduleAtFixedRate(TimerTask task, long delay, long period):delay時間後開始運行任務。並每隔period時間調用任務一次。

(6)void java.util.Timer.scheduleAtFixedRate(TimerTask task, Date firstTime, long period):第一次在指定firstTime時間點運行任務。之後每隔period時間調用任務一次。

(7)void java.util.Timer.cancel():終止該Timer

(8)boolean java.util.TimerTask.cancel():終止該TimerTask

這些scheduleXXX方法中,除了(1)(2)外,其它都能夠反復調用任務,基本的區別就是schedule和scheduleAtFixedRate的區別。


schedule()方法更註重保持間隔時間的穩定:保障每隔period時間可調用一次。


scheduleAtFixedRate()方法更註重保持運行頻率的穩定:保障多次調用的頻率趨近於period時間。假設某一次調用時間大於period,下一次就會盡量小於period。以保障頻率接近於period


3、Timer類的使用示列

首先創建一個任務:

<pre name="code" class="java">import java.util.TimerTask;
public class MyTask extends TimerTask{
     private int id;
     public MyTask(int id){
         this.id = id;
     }
     public void run(){
         System.out.println("線程" + id + ":正在運行");
         //System.gc();
     }
}


main函數代碼:

import java.util.Date;
import java.util.Timer;
public class Test{
    public static void main(String[] args){
        Timer timer = new Timer();
        timer.schedule(new MyTask(1), 5000);// 5秒後啟動任務
        MyTask secondTask = new MyTask(2);
        timer.schedule(secondTask, 1000, 3000);
        // 1秒後啟動任務,以後每隔3秒運行一次線程
        Date date = new Date();
        timer.schedule(new MyTask(3), new Date(date.getTime() + 1000));
        //      以date為參數,指定某個時間點運行線程
        //      timer.cancel();
        //      secondTask.cancel();
        System.out.println("main thread 結束!");
        }
}



JAVA隨筆篇一(Timer源代碼分析和scheduleAtFixedRate的使用)