• JDK Timer & TimerTask


    Timer & TimerTask

    @(Base)[JDK, Timer, TimerTask]

    Timer schedule(动词) task在后台执行。这个Task可能是只执行一次的task,也可能是按照一定规律执行的task。这也是JDK1.3提供的一个非常老的工具类

    • 对于每一个维持schedule的Timer对象来说,内部都只有一个线程顺序执行所有的task。所以每一个客户端提交的task需要尽可能快的完成。如果中间有个线程执行时间非常久,就会hogs起线程,然后面的线程都delay,这样会导致后续处理都很凌乱,让他们全部弄成一团在执行。

    • 当最后持有Timer引用的Object gc掉之后,并且所有的任务已经执行完了之后,timer的execution thread会gracefully终止(然后被垃圾回收)。这个时间可以变得无限长。这个execution线程并不是daemon的。所以他可以让你的application无法终止。如果调用方想要尽快终止程序,可以调用caller的cancel方法。

    • 如果timer的execute的线程异常终止,例如,当他的stop方法被调用的时候,当你再提交一个task进来的时候,就会抛出IllegalStateExcetpion,因为Timer的cancel方法已经被调用了。

    • 这个类是线程安全的。

    • 这个class通过Object.wait方法来调度任务。

    注意: java 1.5 引入的并发包,中有一个ScheduledThreadPoolExecutor,是一个线程池,可以提供固定比率,或者时长的task。


    Binary Heap

    二叉堆是一种经过排序的完全二叉树,其中任一非终端节点的数据值均不大于(或不小于)其左孩子和右孩子节点的值。 —— 维基百科

    • 最大堆和最小堆是二叉堆的两种形式。
    • 最大堆:根结点的键值是所有堆结点键值中最大者。
    • 最小堆:根结点的键值是所有堆结点键值中最小者。
    • 最小堆,就是用于实现优先级队列的。
    • 对于节点N,那么他的两个子节点就是2n, 2n+1,n为数组位置

    Insert

    首先插入尾部,然后一直与index/2,比较交换。

    1. 6 --> [6]
    2. 9 --> [6,9]
    3. 4 --> [6,9,4] --> 4 < arr[3/2-1] --> change(arr[0], arr[2]) --> [4,9,6]
    4. 7 --> [4,9,6] --> 7 < arr[4/2-1] --> change(arr[1], arr[3]) --> [4,7,6,9]
    5. 5 --> [4,7,6,9,5] --> 5 < arr[5/2-1] --> change[arr[1], arr[4]] --> [4,5,6,9,7]
    6. 1 --> [4,5,6,9,7,1] --> 1 < arr[3-1] --> change[arr[2], arr[5]]

    每次插入完成之后总能保证第一个是最小的,这个交换操称为fixUp,或者叫ShiftUp。

    DELETE MIN

    交换队头和队尾,然后删除队尾,然后比较index2, index+2 交换到最小。

    1. [1,5,4,9,7,6] --> [6,5,4,9,7,1] --> [6,5,4,9,7] --> [4,5,6,9,7]
      这个操作成为fixDown,或者ShiftDown。

    PERFORMANCE

    log(n) for add,removeMin,rescheduleMin.
    constant time performance for the getMin operation.

    LifeCycle

    Constructor

    新建TimerThread调度程序。执行mainLoop()

    public void run() {
       try { mainLoop(); }
       finally { clean(); }
    }
    

    MainLoop

    等待在队列上,有值唤醒后取出min操作.

    while (true) {
       sync(queue) {
          while (queue.isEmpty()) { // avoid furious weak up
             queue.wait();          // point 1
          }
          task = queue.getMain();
          sync (task) { // avoid out-side modify // point 2
              // do some cancel check
              if (taskFired = (executionTime <= currentTime)) {
                 queue.rescheduleMin(); // or queue.removeMin();  
              }       
          }
          if (!taskFired) { // point3
             queue.wait(executionTime)
          }
       }
       if (taskFired) { // point4
           task.run()
       }
    }
    

    这段小代码还是很精悍。

    • Point 1: 利用queue对象的wait/notify做了通知模型,当有新任务的时候就会唤醒
    • Point 2: 锁定task对象,避免task对象的内部状态被别人更改,当确定完状态之后,外部更改也就无效了,并且只是改状态的时候加锁
    • Point 3: 当前task的执行时间还不到的时候,挂在queue对象上睡,为什么挂在queue对象上睡呢,这一点很重要,当有新任务进来的时候可以响应到。
    • Point 4: 唤醒之后,如果还不够时间,就进入下一次循环。否则如果够了的话就执行。

    schedule

    sync (queue) {
       sync(task) {
          // change state and nextTime
       }
       queue.add(task)
       if (queue.getMin() == task) {
          queue.notify();
       }
    }
    

    cancel Timer

    synchronized(queue) {
        thread.newTasksMayBeScheduled = false;
        queue.clear();
        queue.notify();  // In case queue was already empty.
    }
    

    cancel one Time Task

    sync(this.lock) {
       this.state = CANCEL;
    } 
    

    purge

    清除所有已经被cancel的task,一般小程序都不需要使用。

    sync (queue) {
       for (item in queue) {
           queue.remove(item); // change current with the last
       }
       reindex();
    }
    

  • 相关阅读:
    文档加载完后执行相关事件
    流程步骤(备用)
    浏览器常见内核
    修改!important定义的样式(2)
    样式被!important 后修改的方法
    产生BFC环境的几种方式
    当我们访问一个网址后发生了什么?
    Java并发基础--线程通信
    Java 集合学习--ArrayList
    Java并发基础--线程安全
  • 原文地址:https://www.cnblogs.com/maxmys/p/5180272.html
Copyright © 2020-2023  润新知