Timer源码浅析

java.util.Timer主要使用了Timer和TimerTask两个类。Timer内部有TimerThread和TaskQueue两个内部类,在创建Timer对象的时候会启动TimerThread线程,不断地从TaskQueue任务队列中取出头任务并执行,而Timer的各种schedule方法负责把TimerTask加入到队列中,使用了生产者消费者模型。

1.TimerTask

public abstract class TimerTask implements Runnable {
	final Object lock = new Object(); // 锁
    int state = VIRGIN; // VIRGIN、SCHEDULED、 EXECUTED、CANCELLED四种状态
    long nextExecutionTime; // 执行时间
    long period = 0// 正值固定频率执行、负值固定延迟执行、0表示不重复执行
    public abstract void run();
}

2.Timer

private final TaskQueue queue = new TaskQueue(); // 内部类,优先队列
private final TimerThread thread = new TimerThread(queue); // 内部类,用来执行任务的线程

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;

    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");
            // 传入的时间作为下次执行时间,状态改为SCHEDULED
            task.nextExecutionTime = time;
            task.period = period;
            task.state = TimerTask.SCHEDULED;
        }

        // 将任务加入队列中,如果该任务成为头任务,则唤醒队列。这包括两种情况:1、队列为空,唤醒等待的队列2、队列的头任务还没到执行时间进行wait,唤醒队列并重新进入mainloop循环
        queue.add(task);
        if (queue.getMin() == task)
            queue.notify();
    }
}

// 终止Timer。将执行线程的newTasksMayBeScheduled置为false,清空队列,并通知
public void cancel() {
    synchronized(queue) {
        thread.newTasksMayBeScheduled = false;
        queue.clear();
        queue.notify();  
    }
}

3.TimerThread

// class TimerThread extends Thread
// 主要方法是mainloop,死循环,每次从队列中取出任务进行执行
private void mainLoop() {
    while (true) {
        try {
            TimerTask task;
            boolean taskFired;
            synchronized(queue) {
                // 如果队列为空则等待
                while (queue.isEmpty() && newTasksMayBeScheduled)
                    queue.wait();
                if (queue.isEmpty())
                    break; // 走到这里说明Timer被终止了,执行线程跳出循环

                // 队列非空取出头任务
                long currentTime, executionTime;
                task = queue.getMin();
                synchronized(task.lock) {
                    // 如果任务状态是CANCELLED,从队列中移除该任务,重新进入循环
                    if (task.state == TimerTask.CANCELLED) {
                        queue.removeMin();
                        continue;  
                    }
                    currentTime = System.currentTimeMillis();
                    executionTime = task.nextExecutionTime;
                    // 如果执行时间小于等于当前时间则taskFired为true,任务状态改为EXECUTED
                    if (taskFired = (executionTime<=currentTime)) {
                        if (task.period == 0) { // 不是重复执行的任务,进行移除
                            queue.removeMin();
                            task.state = TimerTask.EXECUTED;
                        } else { // 反复执行的任务,进行再调度。如果是固定延迟,下次执行时间为当前时间加上任务周期,如果是固定频率,下次执行时间为执行时间加上任务周期
                            queue.rescheduleMin(
                              task.period<0 ? currentTime   - task.period
                                            : executionTime + task.period);
                        }
                    }
                }
                // 如果下次执行时间大于当前时间,进行等待。要么等新任务加入并成为头任务唤醒,要么等够时间自己醒过来
                if (!taskFired) 
                    queue.wait(executionTime - currentTime);
            }
            // 执行任务
            if (taskFired) 
                task.run();
        } catch(InterruptedException e) {
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值