java单线程定时器任务学习笔记

单线程模式(由 Timer和TimerTask 协同实现)

  使用util包下面的Timer工具,简单看一下Timer类的组成。

  

  queue: TaskQueque,本质是一个 TimerTask数组,初始化大小为 128

  thread:TImerThread ,本质就是一个线程,Timer单线程定时任务的执行线程

  ....  , 其他以后再看

  其中,Timer中有六个方法

  

  两个参数的方法,一个是设置任务开始延迟时间,一个是设置任务开始的时间。都是一次性任务。

  有三个参数的方法比两个参数的方法多个long类型的间隔时间参数。其中能定时执行的原理是 , mianLoop()里面是个死循环

  

    下面讲一下这两个方法的差别

  

    

    再仔细分析 , 下面这段代码的流程,在详细分析一下

              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) {
              // 当前任务为取消状态,就从queque中去除当前任务
if (task.state == TimerTask.CANCELLED) {
                // 去除第一个元素 queue.removeMin();
continue; // No action required, poll queue again } currentTime = System.currentTimeMillis(); executionTime = task.nextExecutionTime;
                //当 当前时间>=应该执行的时间, 任务就激活
if (taskFired = (executionTime<=currentTime)) {
                // 如果period == 0说明是一次性任务,从queque去除(执行在下面,不要担心不会执行,这里先去除)
if (task.period == 0) { // Non-repeating, remove queue.removeMin(); task.state = TimerTask.EXECUTED; } else { // Repeating task, reschedule

                   // 重新设置task的nextExecutionTime,schedule传进来的是负数, schuduleAtFixedRate是正数 , 设置完后还会根据 nextExecutionTime进行排序 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();

  

其中 rescheduleMin 中的排序逻辑如下



由此可见,会在queue里面选出一个下次执行时间最小的task放到队首

执行结果借鉴如下


其中 task1是schedule执行的 , nextExecutionTime = currentTime + period
其中 task是scheduleAtFixedRate执行的  ,  nextExecutionTime = executionTime(上一个) + period

可见,除了新添加task放到队首外,其余每次都是选最早的那个任务开始执行


  

原文地址:https://www.cnblogs.com/liujiaa/p/8082045.html