今天修復了一個定時任務,看了點源碼,記錄一下。 主要是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方法源碼能夠看出:源碼
public void schedule(TimerTask task, Date time) { sched(task, time.getTime(), 0); }
sched、mainLoop方法源碼能夠看出:it
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
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
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
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方法源碼能夠看出: