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. ubuntu中为hive配置远程MYSQL database

    一.安装mysql $ sudo apt-get install mysql-server 启动守护进程 $ sudo service mysql start 二.配置mysql服务与连接器 1.安装 ...

  2. 《A First Course in Probability》-chaper5-连续型随机变量-随机变量函数的分布

    在讨论连续型随机变量函数的分布时,我们从一般的情况中(讨论正态分布的文章中提及),能够得到简化版模型. 回忆利用分布函数和概率密度的关系求解随机变量函数分布的过程,有Y=g(x),如果g(x)是严格单 ...

  3. 一段SQL代码的压缩:从974行到96行,十倍压缩

    涉及到数据库拆分,需要将相关表的JOIN SQL剥离. 剥离过程中,发现了这么个SQL XML.整个SQL 974 行,分为6个函数.读起来费劲无比. <?xml version="1 ...

  4. Centos6.4 openNebula

    OpenNebula 是一套开源的云计算基础管理工具,用来方便管理员在数据中心统一部署.创建.分配和管理大量的虚拟机,企业数据中心可以利用这套工具搭建自己的私有云,为 自己内部提供 IaaS 服务,类 ...

  5. Area - POJ 1265(pick定理求格点数+求多边形面积)

    题目大意:以原点为起点然后每次增加一个x,y的值,求出来最后在多边形边上的点有多少个,内部的点有多少个,多边形的面积是多少. 分析: 1.以格子点为顶点的线段,覆盖的点的个数为GCD(dx,dy),其 ...

  6. lightoj 1094 Farthest Nodes in a Tree 【树的直径 裸题】

    1094 - Farthest Nodes in a Tree PDF (English) Statistics Forum Time Limit: 2 second(s) Memory Limit: ...

  7. jni cocos2d-x移植到android:helloworld

    前面搭建好了android开发环境 jni开发环境,那么就来用一用目前火热的cocos2d的游戏引擎吧 所需资料: cocos2d :下载地址  http://www.oschina.net/p/co ...

  8. android实习程序7——通话记录显示

    下载SQLiteSpy.exe 打开模拟器5554 打开perspective,选择DDMS 打开Devices,确认存在emulator-5554 打开file Explorer 打开data文件夹 ...

  9. hadoop ssh无密码登陆

    VM DHCP蛋疼了,这次整个static... scp

  10. Unicode与UTF-8互转(C语言实现)

    1. 基础 1.1 ASCII码 我们知道, 在计算机内部, 所有的信息最终都表示为一个二进制的字符串. 每一个二进制 位(bit)有0和1两种状态, 因此八个二进制位就可以组合出 256种状态, 这 ...