java线程之Timer实现原理解析

2018-03-11  本文已影响0人  dimdark

1. 整体图解

整体结构图解

2. 包含任务执行逻辑的 TimerTask 抽象类

TimerTask的生命周期 TimerTask类的属性解析 TimerTask类的实例方法

3. 任务队列 TaskQueue

TaskQueue 内部采用最小堆来实现优先队列, 其各种操作的复杂度不超过O(logn)

TaskQueue类的属性

4. 执行任务的线程类 TimerThread

执行任务的线程类 TimerThread 继承 Thread 类, 用来执行任务队列中的任务, 因此, Timer 类调度的所有任务都是在单线程中按执行时间先后顺序执行的

mainloop 方法详细解释如下:

private void mainLoop() {
        while (true) {
            try {
                TimerTask task;
                boolean taskFired;
                synchronized (queue) {
                    // 任务队列为空, 让当前执行线程放弃queue锁
                    while (queue.isEmpty() && newTasksMayBeScheduled) {
                        queue.wait();
                    }
                    // 执行期间发现任务队列为空, 即没有任务需要执行, 因此跳出循环
                    if (queue.isEmpty()) {
                        break;
                    }
                    long currentTime, executionTime;
                    task = queue.getMin();
                    synchronized (task.lock) {
                        if (task.state == TimerTask.TimerTaskStatus.CANCELLED) {
                            queue.removeMin();
                            continue; // 开始下一次循环去执行下一个任务
                        }
                        currentTime = System.currentTimeMillis();
                        executionTime = task.nextExecutionTime;
                        if (taskFired = (executionTime <= currentTime)) { // 任务的开始时间早于当前时间, 则立即执行
                            if (task.period == 0) { // 非周期型任务
                                queue.removeMin();
                                task.state = TimerTask.TimerTaskStatus.EXECUTED;
                            } else { // 周期型任务
                                // schedule 与 scheduleAtFixedRate 的区别体现在这里
                                // 当执行时间早于当前时间时, schedule系列方法执行时没有追赶性, scheduleAtFixedRate系列方法执行时具有追赶性
                                queue.rescheduleMin(task.period < 0 ? currentTime - task.period : executionTime + task.period);
                            }
                        }
                    }
                    if (!taskFired) { // 还未到时间执行任务
                        queue.wait(executionTime - currentTime);
                    }
                }
                if (taskFired) { // 可以执行任务(注意: 没有锁)
                    task.run();
                }
            } catch (InterruptedException e) {
            }
        }
    }

5. Timer 类解析

Timer类的属性 Timer类的构造方法 cancel方法 schedule系列方法 scheduleAtFixedRate系列方法

schedulescheduleAtFixedRate 方法的具体执行逻辑放在 sched 方法上:

private void sched(TimerTask task, long time, long period) {
        // 验证参数是否正确
        if (time < 0) {
            throw new IllegalArgumentException("Illegal execution time.");
        }
        if (Math.abs(period) > (Long.MAX_VALUE >> 1)) {
            period >>= 1;
        }
        // 将任务task的属性设置好并存放在任务队列queue上
        synchronized (queue) {
            if (!thread.newTasksMayBeScheduled) {
                throw new IllegalArgumentException("Timer already cancelled.");
            }
            synchronized (task.lock) {
                if (task.state != TimerTask.TimerTaskStatus.VIRGIN) {
                    throw new IllegalArgumentException("Task already scheduled or cancelled!");
                }
                task.nextExecutionTime = time;
                task.period = period;
                task.state = TimerTask.TimerTaskStatus.SCHEDULED;
            }
            queue.add(task);
            // 若加入任务前队列为空则要通知执行任务的线程, 使其从WAITING状态切换为RUNNABLE状态
            if (queue.getMin() == task) {
                queue.notify(); 
            }
        }
   }

注意: schedulescheduleAtFixedRate 方法的区别在于当执行时间早于当前时间时, schedule 方法不具有追赶性, 而 scheduleAtFixedRate 方法具有追赶性;

上一篇 下一篇

猜你喜欢

热点阅读