ScheduleThreadPoolExecutor源码分析(一)

Java中ScheduleThreadPoolExecutor主要用于执行延迟任务或者按照一定的频率执行任务。其中scheduleAtFixedRate函数是按照一定频率执行任务,scheduleWithFixedDelay可以根据延迟一定时间再执行任务。本文将参考ScheduleThreadPoolExecutor的源码来剖析其为什么能够支持延迟并按照固定频率执行任务。

ScheduleThreadPoolExecutor之所以能够延迟并按照一定频率执行任务主要依靠其内部封装的两个内部类,ScheduledFutureTask和DelayedWorkQueue。其中ScheduledFutureTask继承了FutureTask类,因此其可以封装继承了Runable或Callable接口的任务。而DelayedWorkQueue则为一个延迟队列,其利用最小堆实现,需要首先执行的任务在堆顶,这样每次执行任务时只需要获取堆顶的任务即可。

ScheduledFutureTask:

ScheduledFutureTask继承了FutureTask,因此其能够被ScheduledExecutorService执行。下面看一下ScheduledFutureTask的一些重要属性:

  • int heapIndex:表示改任务在DelayedWorkQueue队列中的索引。由于DelayedWorkQueue是由最小堆构建的,为了提高查找的速度,在封装的Task里引入该字段,可以使查找时间复杂度降到O(1)。
  • private long time:表示该任务执行的时间,在getDelay()函数中根据unit.convert(time - now(), NANOSECONDS)来获得任务还需要多长时间才能执行。同时DelayedWorkQueue中也是根据该字段来维护最小堆的。
  • private final long period:执行重复任务的时间。正数表示按照一定的速率执行任务,负数表示按照一定的延迟执行任务,0表示任务不重复执行。
  • RunnableScheduledFuture outerTask = this:指定该任务。
  • private final long sequenceNumber:任务进入队列的顺序,保证队列的FIFO

对于ScheduledFutureTask的方法,最主要的是compareTo和getDelay和setNextRunTime方法。

  •   public long getDelay(TimeUnit unit) {
    return unit.convert(time - now(), NANOSECONDS);
    }

    该方法主要是用来获得任务需要执行时的延迟时间,其在DelayedWorkQueue中的offer函数中有重要的运用。

    public int compareTo(Delayed other) {
    if (other == this) // compare zero if same object
    return 0;
    if (other instanceof ScheduledFutureTask) {
    ScheduledFutureTask<?> x = (ScheduledFutureTask<?>)other;
    long diff = time - x.time;
    if (diff < 0)
    return -1;
    else if (diff > 0)
    return 1;
    else if (sequenceNumber < x.sequenceNumber)
    return -1;
    else
    return 1;
    }
    long diff = getDelay(NANOSECONDS) - other.getDelay(NANOSECONDS);
    return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;
    }

    compareTo方法主要用于DelayQueue中最小堆的排序,其首先根据任务执行时间来判断,如果任务执行时间相同则按照队列的FIFO规则进行判断。

  •   private void setNextRunTime() {
    long p = period;
    if (p > 0)
    time += p;
    else
    time = triggerTime(-p);
    }

    setNextRunTIme()方法主要是为需要重复执行的任务设置下次执行的时间,当period > 0时表示任务是按照一定速率执行的,只需要将本次执行时间加上间隔时间即可。当period < 0时表示任务是延期执行的,需要调用triggerTime来获得下次执行时间。下面是triggerTime函数的实现:

    long triggerTime(long delay) {
    return now() +
    ((delay < (Long.MAX_VALUE >> 1)) ? delay : overflowFree(delay));
    } /**
    * Constrains the values of all delays in the queue to be within
    * Long.MAX_VALUE of each other, to avoid overflow in compareTo.
    * This may occur if a task is eligible to be dequeued, but has
    * not yet been, while some other task is added with a delay of
    * Long.MAX_VALUE.
    */
    private long overflowFree(long delay) {
    Delayed head = (Delayed) super.getQueue().peek();
    if (head != null) {
    long headDelay = head.getDelay(NANOSECONDS);
    if (headDelay < 0 && (delay - headDelay < 0))
    delay = Long.MAX_VALUE + headDelay;
    }
    return delay;
    }

    由上面的代码可知,对于延迟执行的任务,执行时间是当前时间加上延迟时间。而为了防止在conpareTo进行比较时数值过大,延迟时间又是根据队列中下一个要执行的任务的执行时间来获得。下一篇讲介绍DelayQueue的详细实现。

ScheduleThreadPoolExecutor源码分析的更多相关文章

  1. ScheduleThreadPoolExecutor源码分析(二)

    DelayedWorkQueue: DelayedWorkQueue实现了BlockingQueue接口,因此其可以作为线程池的任务队列.BlockingQueue的主要属性有以下几个: privat ...

  2. ABP源码分析一:整体项目结构及目录

    ABP是一套非常优秀的web应用程序架构,适合用来搭建集中式架构的web应用程序. 整个Abp的Infrastructure是以Abp这个package为核心模块(core)+15个模块(module ...

  3. HashMap与TreeMap源码分析

    1. 引言     在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...

  4. nginx源码分析之网络初始化

    nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解,本文主要通过nginx的源代码来分析其网络初始化. 从配置文件中读取初始化信息 与网 ...

  5. zookeeper源码分析之五服务端(集群leader)处理请求流程

    leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...

  6. zookeeper源码分析之四服务端(单机)处理请求流程

    上文: zookeeper源码分析之一服务端启动过程 中,我们介绍了zookeeper服务器的启动过程,其中单机是ZookeeperServer启动,集群使用QuorumPeer启动,那么这次我们分析 ...

  7. zookeeper源码分析之三客户端发送请求流程

    znode 可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个功能是zookeeper对于应用最重要的特性,通过这个特性可以实现的功能包括配置的 ...

  8. java使用websocket,并且获取HttpSession,源码分析

    转载请在页首注明作者与出处 http://www.cnblogs.com/zhuxiaojie/p/6238826.html 一:本文使用范围 此文不仅仅局限于spring boot,普通的sprin ...

  9. ABP源码分析二:ABP中配置的注册和初始化

    一般来说,ASP.NET Web应用程序的第一个执行的方法是Global.asax下定义的Start方法.执行这个方法前HttpApplication 实例必须存在,也就是说其构造函数的执行必然是完成 ...

随机推荐

  1. 【单页应用】view与model相关梳理(转载)

    [单页应用]view与model相关梳理 前情回顾 根据之前的学习,我们形成了一个view与一个messageCenterview这块来说又内建了一套mvc的东西,我们这里来理一下首先View一层由三 ...

  2. AKKA初体验

    关于thread和actor下面这段话讲的很好Experienced developers have learned to be very careful with unrestricted thre ...

  3. ios 中介者模式

    中介设计模式在ios中普片应用于视图迁移 1,从xib中生成object对象,中介类为n个不同对象 @property(nonatomic,retain)IBOutlet NSObject *ob; ...

  4. 6步骤实现CentOS系统环境精简优化

    6步骤实现CentOS系统环境精简优化 发布时间:2014-11-03 14:59:27   编辑:AHLinux.com 第一步.删除不必要的自带软件包yum remove Deployment_G ...

  5. Java 5种字符串拼接方式性能比较

    http://blog.csdn.net/kimsoft/article/details/3353849 import java.util.ArrayList; import java.util.Li ...

  6. java小算法—大衍数列

    题目:    中国古代文献中,曾记载过“大衍数列”, 主要用于解释中国传统文化中的太极衍生原理. 它的前几项是:0.2.4.8.12.18.24.32.40.50 ... 其规律是:对偶数项,是序号平 ...

  7. 食品药检所LIMS需求分析说明书

    1.XX市食品药检所LIMS系统需求分析... 5 1.1检验业务流程... 5 1.1.1样品受理... 5 1.1.1.1选择受理任务... 5 1.1.1.2录入检品信息... 5 1.1.1. ...

  8. WebSocket与Tcp连接

    最近做了一个项目,客户端为WebSocket页面,服务器端为Tcp控制台 .将代码贴出来,供需要的参考. 1.服务器端代码 其中服务器的Session使用了第三方插件,为TCP连接. 2.客户端代码如 ...

  9. 【转】YUV420P的格式以及转换为RGB565的代码(Android摄像头的输出一般为YUV420P)

    http://blog.csdn.net/daisyhd/article/details/38866809 static void cvt_420p_to_rgb565(int width, int  ...

  10. redis学习大全

     http://blog.csdn.net/menergy/article/details/17577985 http://blog.sina.com.cn/s/blog_64008ed70102uy ...