Timer和TimerTask解读

本文详细解析了JDK Timer类的内部实现机制,包括其基于单线程的调度方式,schedule方法的具体流程,TaskQueue对象的使用以及TimerThread线程的执行逻辑。通过代码分析,揭示了Timer类如何高效地安排和执行定时任务。
摘要由CSDN通过智能技术生成

测试Timer的代码如下:

  Timer timer = new Timer();

  timer.schedule(new TimerTask(){

   @Override

   public void run() {

    System.out.println("aaaaa");

   }

  }, 0);

Timer类中有一个TaskQueue和一个TimerThread 线程对象,

    private final TaskQueue queue = new TaskQueue();

    private final TimerThread thread = new TimerThread(queue);

这里也证明了JDK自带的Timer实现是基于单线程的调度。

Timer的构造方法将thread启动了起来

    public Timer(String name) {

        thread.setName(name);

        thread.start();

    }


调用Timer类的schedule方法的代码如下:

    public void schedule(TimerTask task, long delay) {

        if (delay < 0)

            throw new IllegalArgumentException("Negative delay.");

        sched(task, System.currentTimeMillis()+delay, 0);

    }

都会调用到一个内部private的sched方法,代码如下

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

        }

    }

将传入的TimerTask 的实现调用TaskQueue对象的add方法放入到queue里面,

我们来看看这个add方法:

    void add(TimerTask task) {

        // Grow backing store if necessary

        if (size + 1 == queue.length)

            queue = Arrays.copyOf(queue, 2*queue.length);


        queue[++size] = task;

        fixUp(size);

    }

首先只是简单的将任务队列中的数组对象++放入,接下来调用了fixUp方法进行调整,我们猜测这个方法就是将queue中的任务根据执行时间的优先级进行调整,代码如下:

    private void fixUp(int k) {

        while (k > 1) {

            int j = k >> 1;

            if (queue[j].nextExecutionTime <= queue[k].nextExecutionTime)

                break;

            TimerTask tmp = queue[j]; queue[j] = queue[k]; queue[k] = tmp;

            k = j;

        }

    }

这个方法主要就是通过一个折半查找的算法将当前任务期待执行的时间和折半取到的任务的执行时间进行对比匹配,从而将当前的任务放到数组中的一个合适的位置,处理完成后返回。

下面我们看看Timer 内部的 private final TimerThread thread = new TimerThread(queue);线程启动以后的执行逻辑,他的run方法调用了mainLoop方法:

这个方法首先判断queue的是不是空,如果是空的话就调用queue对象的wait方法释放锁并等待。如果queue不为空就调用queue的queue.getMin()方法取得队列头部的TimerTask任务,

然后将任务期待的执行时间executionTime和当前时间currentTime进行比较,如果executionTime<=currentTime先拿到TimerTask任务的period的值,如果为0说明是执行一次的任务,如果period下于0

说明是通过Timer的schedule方法提交的任务,如果大于0说明是通过Timer的scheduleAtFixedRate方法提交的任务,他们的不同在于设置任务下一次执行的时间(就是修改queue中TimerTask的nextExecutionTime的值)相对的量不同,代码如下:

queue.rescheduleMin(

                                  task.period<0 ? currentTime - task.period

                                                : executionTime + task.period)

scheduleAtFixedRate方法是相对executionTime 

schedule方法是相对的currentTime时间提交的

处理完成后判断如果executionTime<=currentTime直接执行这个任务;

如果如果executionTime>currentTime的值就调用queue的

queue.wait(executionTime - currentTime);

方法限时等待一定时间之后重新执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值