天天看點

Java Timer&TimerTask源碼分析

這個定時執行任務的類是個單線程的,具體使用可以參考之前的文章。現在看看實作原理。

字段:

private final TaskQueue queue = new TaskQueue();
private final TimerThread thread = new TimerThread(queue);
           

定義了一個TaskQueue.以及一個TimerThread. 這個TaskQueue是一個TimerTask對象所構造的優先隊列。TimerThread用于執行TaskQueue中的TimerTask.

構造函數:

public Timer() {
        this("Timer-" + serialNumber());
}
public Timer(String name) {
        thread.setName(name);
        thread.start();
}
private final static AtomicInteger nextSerialNumber = new AtomicInteger();
private static int serialNumber() {
        return nextSerialNumber.getAndIncrement();
}
           

構造函數做了如下幾件事情:

1 定義了一個TimerThread線程對象的名稱。

2 啟動了TimerThread線程。

看看TimerThread對象的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
            }
        }
    }
           

這裡執行了一個mainLoop方法。

private void mainLoop() {
        while (true) {
            try {
                TimerTask task;
                boolean taskFired;
                synchronized(queue) {
                    // Wait for queue to become non-empty
                    while (queue.isEmpty() && newTasksMayBeScheduled)
                        queue.wait();
                    if (queue.isEmpty())
                        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 == ) { // Non-repeating, remove
                                queue.removeMin();
                                task.state = TimerTask.EXECUTED;
                            } else { // Repeating task, reschedule
                                queue.rescheduleMin(
                                  task.period< ? 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) {
            }
        }
    }
           

在構造函數啟動TimerThread線程後,進入這個while循環,鎖定了queue隊列,在這裡判斷隊列是否為空,如果為空,則Timer主線程一直等待。

當運作了Timer的schedule方法後,這個方法如下:

public void schedule(TimerTask task, long delay) {
        if (delay < )
            throw new IllegalArgumentException("Negative delay.");
        sched(task, System.currentTimeMillis()+delay, );
}
private void sched(TimerTask task, long time, long period) {
        if (time < )
            throw new IllegalArgumentException("Illegal execution time.");

        // Constrain value of period sufficiently to prevent numeric
        // overflow while still being effectively infinitely large.
        if (Math.abs(period) > (Long.MAX_VALUE >> ))
            period >>= ;

        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();
        }
}
           

這裡鎖定了目前task對象并設定執行時間,狀态,周期等,然後将這個task添加進queue。如果這個task在隊列的第一個元素上,則喚醒隊列進行執行。這裡主線程會進入在wait方法後繼續執行。

這裡繼續看主線程的執行:

鎖定這個task對象并且判斷狀态。如果這個task沒有被cancelled掉,那麼會取得目前時間和task的執行時間,如果目前時間大于task的執行時間且task周期為0,則從隊列中删除這個task,并且設定狀态為已執行,否則這裡重新schedule這個task。如果task沒有到執行的時間,則queue等待。否則直接調用task的run方法。

從這裡來看,Timer是單線程來執行queue的,是以有明顯缺憾就是:

queue是按照順序來執行,如果前面的task沒執行完,後面的就要延期了。

如果前面的task抛異常導緻timer線程停止,那麼後面的task也不會被執行了。