Timer定時

今天修復了一個定時任務,看了點源碼,記錄一下。 主要是Timer的6個方法的分析,首先先看一下這6個方法都調用的方法sched:oop

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

當調用sched方法時, 1.period週期爲正,則任務被安排爲重複執行;若是週期爲零,則任務被安排爲一次性執行;ui

2.當time時間爲過去時間時,若是period週期爲正,則按照‘過去時間time+period週期’執行;若是週期爲負, 按照 ‘當前時間+period週期’執行,即執行當前時間之後的任務。code

能夠參考源碼以下:rem

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 == 0) { // Non-repeating, remove
                                queue.removeMin();
                                task.state = TimerTask.EXECUTED;
                            } else { // Repeating task, reschedule
			    //這裏判斷period,爲正返回executionTime + task.period
			    //爲負返回currentTime   - task.period
                                queue.rescheduleMin(
                                  task.period<0 ? 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) {
            }
        }
    }
}

明白了上面的原理,接下來就比較容易理解6個方法了。get

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

sched、mainLoop方法源碼能夠看出:源碼

  • period週期爲0,delay延遲後,執行一次
public void schedule(TimerTask task, Date time) {
        sched(task, time.getTime(), 0);
    }

sched、mainLoop方法源碼能夠看出:it

  • time爲過去時間,直接執行;
  • time爲將來時間,等到時間達time時執行。
public void schedule(TimerTask task, long delay, long period) {
        if (delay < 0)
            throw new IllegalArgumentException("Negative delay.");
        if (period <= 0)
            throw new IllegalArgumentException("Non-positive period.");
        sched(task, System.currentTimeMillis()+delay, -period);
    }

sched、mainLoop方法源碼能夠看出:io

  • 延遲delay,開始執行
public void schedule(TimerTask task, Date firstTime, long period) {
        if (period <= 0)
            throw new IllegalArgumentException("Non-positive period.");
        sched(task, firstTime.getTime(), -period);
    }

sched、mainLoop方法源碼能夠看出:thread

  • firstTime爲過去時間,則執行當前時間之後的任務;
  • firstTime爲將來時間,則等到到達firstTime時間開始執行任務。
public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
        if (delay < 0)
            throw new IllegalArgumentException("Negative delay.");
        if (period <= 0)
            throw new IllegalArgumentException("Non-positive period.");
        sched(task, System.currentTimeMillis()+delay, period);
    }

sched、mainLoop方法源碼能夠看出:require

  • 延遲delay時間後,開始執行任務
public void scheduleAtFixedRate(TimerTask task, Date firstTime,
                                    long period) {
        if (period <= 0)
            throw new IllegalArgumentException("Non-positive period.");
        sched(task, firstTime.getTime(), period);
    }

sched、mainLoop方法源碼能夠看出:

  • firstTime若是爲過去時間,則從過去時間開始執行,並以period爲週期一直執行;
  • firstTime若是去將來時間,則等到firstTime到達時,開始執行,並以period爲週期一直執行。
  • 這裏能夠看出和4的區別,當firstTime爲過去時間時,6補了從設定時間開始的任務,而4只管執行如今及之後的任務。
  • 若是firstTime爲將來時間,四、6沒有區別
相關文章
相關標籤/搜索