Timer和TimerTask解读

来源:互联网 发布:java spring 工厂模式 编辑:程序博客网 时间:2024/05/13 00:29

测试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);

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

0 0
原创粉丝点击