Java Timer&TimerTask源码分析

本文深入剖析了一个单线程定时任务类的实现原理。该类通过一个优先级队列TaskQueue来存放TimerTask,并利用TimerThread线程来执行这些任务。文章详细介绍了其构造函数、任务调度方法以及如何确保任务按预定时间执行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这个定时执行任务的类是个单线程的,具体使用可以参考之前的文章。现在看看实现原理。

字段:

private final TaskQueue queue = new TaskQueue();
private final TimerThread thread = new TimerThread(queue);

定义了一个TaskQueue.以及一个TimerThread. 这个TaskQueue是一个TimerTask对象所构造的优先队列。TimerThread用于执行TaskQueue中的TimerTask.

构造函数:

public Timer() {
        this("Timer-" + serialNumber());
}
public Timer(String name) {
        thread.setName(name);
        thread.start();
}
private final static AtomicInteger nextSerialNumber = new AtomicInteger(0);
private static int serialNumber() {
        return nextSerialNumber.getAndIncrement();
}

构造函数做了如下几件事情:
1 定义了一个TimerThread线程对象的名称。
2 启动了TimerThread线程。

看看TimerThread对象的run方法。

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

这里执行了一个mainLoop方法。

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
                                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) {
            }
        }
    }

在构造函数启动TimerThread线程后,进入这个while循环,锁定了queue队列,在这里判断队列是否为空,如果为空,则Timer主线程一直等待。

当运行了Timer的schedule方法后,这个方法如下:

 public void schedule(TimerTask task, long delay) {
        if (delay < 0)
            throw new IllegalArgumentException("Negative delay.");
        sched(task, System.currentTimeMillis()+delay, 0);
}
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();
        }
}

这里锁定了当前task对象并设置执行时间,状态,周期等,然后将这个task添加进queue。如果这个task在队列的第一个元素上,则唤醒队列进行执行。这里主线程会进入在wait方法后继续执行。
这里继续看主线程的执行:
锁定这个task对象并且判断状态。如果这个task没有被cancelled掉,那么会取得当前时间和task的执行时间,如果当前时间大于task的执行时间且task周期为0,则从队列中删除这个task,并且设置状态为已执行,否则这里重新schedule这个task。如果task没有到执行的时间,则queue等待。否则直接调用task的run方法。

从这里来看,Timer是单线程来执行queue的,因此有明显缺憾就是:
queue是按照顺序来执行,如果前面的task没执行完,后面的就要延期了。
如果前面的task抛异常导致timer线程停止,那么后面的task也不会被执行了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值