Java-定時器(Timer)-分析

定時器的使用

//timer的使用
private void testTimer(){
        //<1>Timer僅延遲執行
        //第一次延時1秒後開始執行任務currentTime=System.currentTimeMillis()+1000,任務執行完後就結束了
        Timer timerDelayOnly = new Timer();
        timerDelayOnly.schedule(new TimerTask() {
            @Override
            public void run() {
				//要執行的任務
            }
        },1000);

        //<2>
        //第一次延時1秒後開始執行任務nextTaskTime=System.currentTimeMillis()+1000,即第一次任務開始執行時間
        //第一次任務完成後下次任務nextTaskTime=System.currentTimeMillis()+3000,即第二次任務開始執行時間
        //第二次任務完成後下次任務nextTaskTime=System.currentTimeMillis()+3000,即第三次任務開始執行時間
        //...
        //此類定時器,在上個任務執行完後,纔會重新計時
        Timer timerDelayAndRate = new Timer();
        timerDelayAndRate.schedule(new TimerTask() {
            @Override
            public void run() {
                //要執行的任務
            }
        },1000,30*1000);

        //<3>
        //第一次延時1秒後開始執行任務nextTaskTime=System.currentTimeMillis()+1000,即第一次任務的執行時間
        //第一次任務完成後下次任務nextTaskTime=nextTaskTime+3000,即第二次任務開始執行時間
        //第二次任務完成後下次任務nextTaskTime=nextTaskTime+3000,即第三次任務開始執行時間
        //...
        //此類定時器,在固定時間線爲起點,重新計時
        Timer timerDelayAtFixedRate = new Timer();
        timerDelayAtFixedRate.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                //要執行的任務
            }
        },1000,30*1000);

        //<4>
        //每天除第一次12是0分0秒,被調起,其他次的任務需要考慮歷史人物的執行時間的總和
        //第一次任務開始執行時間nextTaskTime=timeDate,即第一次任務的執行時間
        //第一次任務完成後下次任務nextTaskTime=System.currentTimeMillis()+1000 * 60 * 60 * 24,即第二次任務的執行時間
        //第二次任務完成後下次任務nextTaskTime=System.currentTimeMillis()+1000 * 60 * 60 * 24,即第三次任務的執行時間
        //...
        //此類定時器,在上個任務執行完後,纔會重新計時
        Timer timerDate= new Timer();
        Calendar calendarDate = Calendar.getInstance();
        calendarDate.set(Calendar.HOUR_OF_DAY, 12); // 控制時
        calendarDate.set(Calendar.MINUTE, 0);// 控制分
        calendarDate.set(Calendar.SECOND, 0);// 控制秒
        Date timeDate = calendarDate.getTime();// 得出執行任務的時間,此處爲今天的12:00:00
        timerDate.schedule(new TimerTask() {
            @Override
            public void run() {
                //要執行的任務
            }
        },timeDate,1000 * 60 * 60 * 24);

        //<5>
        //每天12時0分0秒,任務被執行,不考慮任務的執行時間
        //每天除第一次12是0分0秒,被調起,其他次的任務需要考慮歷史人物的執行時間的總和
        //第一次任務開始執行時間nextTaskTime=timeDate,即第一次任務的執行時間
        //第一次任務完成後下次任務nextTaskTime=extTaskTime+1000 * 60 * 60 * 24,即第二次任務的執行時間
        //第二次任務完成後下次任務nextTaskTime=extTaskTime+1000 * 60 * 60 * 24,即第三次任務的執行時間
        //...
        //此類定時器,在上個任務執行完後,下一個任務的時間爲上一個任務的起始時間+period
        Timer timerAtFixedRate = new Timer();
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.HOUR_OF_DAY, 12); // 控制時
        calendar.set(Calendar.MINUTE, 0);// 控制分
        calendar.set(Calendar.SECOND, 0);// 控制秒
        Date time = calendar.getTime();// 得出執行任務的時間,此處爲今天的12:00:00
        timerAtFixedRate.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                //要執行的任務
            }
        },time,1000 * 60 * 60 * 24);
    }

定時器調用過程

Timer

//Timer 初始化對象時,
private final TaskQueue queue = new TaskQueue();
private final TimerThread thread = new TimerThread(queue);
 public Timer(String name) {
        thread.setName(name);
        thread.start();
}

private void sched(TimerTask task, long time, long period) {
        if (time < 0)
            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 >> 1))
            period >>= 1;

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

TimerThread 的run方法

class TimerThread extends Thread {
    /**
     *新任務可能被執行
     */
    boolean newTasksMayBeScheduled = true;
    private TaskQueue queue;

    TimerThread(TaskQueue queue) {
        this.queue = queue;
    }

    public void run() {
        try {
            mainLoop();
        } finally {
            // Someone killed this Thread, behave as if Timer cancelled
            synchronized(queue) {
                newTasksMayBeScheduled = false;
                queue.clear();  // Eliminate obsolete references
            }
        }
    }

    /**
     * 真正執行定時任務的方法,在run方法中被調起
     */
    private void mainLoop() {
        while (true) {
            try {
                TimerTask task;
                boolean taskFired;
                synchronized(queue) {
                    // Wait for queue to become non-empty
                    //Timer初始化完成thread.start()後,會一直阻塞在這個位置等待
                    //一直等到Timer.sched(...){queue.add(TimerTask;queue.notify();)},阻塞等待纔會結束
                    while (queue.isEmpty() && newTasksMayBeScheduled)
                        queue.wait();
                     //TimerTask.cancel(){queue.clear;newTasksMayBeScheduled=false},會退出循環
                    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
                            //週期性重置task.nextExecutionTime。
                            //task.period<0,上一個任務執行完後,以當前時間currentTime爲基準,往後延時period
                            //task.period>0,與task.nextExecutionTime爲基準,往後延時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) {
            }
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章