ScheduledThreadPoolExecutor继承与基础线程池类ThreadPoolExecutor并实现ScheduledExecutorService接口。

其中ScheduledExecutorService继承与ExecutorService接口并添加了scheduleAtFixedRate和scheduleWithFixedDelay等方法。

两个方法的区别是前者是周期性的按照一定的时间进行任务的执行。如果一个任务执行超过了周期时间,则任务执行完之后会马上进行下一次任务的执行。而后者在这样的情况出现的时候会在任务执行完之后仍然间隔周期时间进行下一次任务的执行。

ScheduledThreadPoolExecutor内部封装了一个ScheduledFutureTask<V>类。该类继承与FutureTask<V>实现RunnableScheduledFuture<V>

ScheduledFutureTask<V>内部有对应的任务的比较器。包含sequenceNumber记录任务进入队列的序号。内部的关键方法为runPeriodic()方法

private void runPeriodic() {

  • boolean ok = ScheduledFutureTask.super.runAndReset();
  • boolean down = isShutdown();
  • // Reschedule if not cancelled and not shutdown or policy allows
  • if (ok && (!down ||
  • (getContinueExistingPeriodicTasksAfterShutdownPolicy() &&
  • !isStopped()))) {
  • long p = period;
  • if (p > 0)
  • time += p;
  • else
  • time = now() - p;
  • ScheduledThreadPoolExecutor.super.getQueue().add(this);
  • }
  • // This might have been the final executed delayed
  • // task.  Wake up threads to check.
  • else if (down)
  • interruptIdleWorkers();
  • }

该方法处理周期性执行的和非周期性执行的任务。其中period传入的值有正有负。这也是scheduleAtFixedRate和scheduleWithFixedDelay对应的区别。最后将相应的任务加入到对应的线程池的阻塞队列中。如果线程池关闭了需要调用对应的线程池关闭的处理。

对应的run方法为:

public void run() {

  • if (isPeriodic())
  • runPeriodic();
  • else
  • ScheduledFutureTask.super.run();
  • }

private void delayedExecute(Runnable command) {
        if (isShutdown()) {
            reject(command);
            return;
        }
        if (getPoolSize() < getCorePoolSize())
            prestartCoreThread();

super.getQueue().add(command);
    }
首次将任务加入到队列中的方法。

public boolean prestartCoreThread() {
        return addIfUnderCorePoolSize(null);
    }

private boolean addIfUnderCorePoolSize(Runnable firstTask) {
        Thread t = null;
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            if (poolSize < corePoolSize && runState == RUNNING)

t = addThread(firstTask);

} finally {

mainLock.unlock();

}

if (t == null)

return false;         t.start();         return true; }

如果当前线程数小于核心线程数。则会新创建一个线程。新创建线程的时候会传入首个任务。

ScheduledThreadPoolExecutor中的默认拒绝策略是AbortPolicy 当任务添加到线程池中被拒绝时,它将抛出 RejectedExecutionException 异常 其它的拒绝策略为:

AbortPolicy         -- 当任务添加到线程池中被拒绝时,它将抛出 RejectedExecutionException 异常。
CallerRunsPolicy    -- 当任务添加到线程池中被拒绝时,会在线程池当前正在运行的Thread线程池中处理被拒绝的任务。
DiscardOldestPolicy -- 当任务添加到线程池中被拒绝时,线程池会放弃等待队列中最旧的未处理任务,然后将被拒绝的任务添加到等待队列中。
DiscardPolicy       -- 当任务添加到线程池中被拒绝时,线程池将丢弃被拒绝的任务。

FutureTask<V>类的内部是通过Sync和Callable<V>来构建相应的任务Sync是对应的同步器继承于AQS(内部基于一个链表的形式来维护一个等待队列,用其内部的Node节点进行构建)。AQS内部的原理感兴趣的的可以看下,此外ReenTrantLock内部的实现则是基于sync和AQS。

此外ScheduledThreadPoolExecutor内部封装了一个DelayedWorkQueue。其内部应用DelayQueue实现。对DelayQueue感兴趣的可以看下。

ScheduledThreadPoolExecutor源码主要部分解析的更多相关文章

  1. MyBatis 源码分析 - 配置文件解析过程

    * 本文速览 由于本篇文章篇幅比较大,所以这里拿出一节对本文进行快速概括.本篇文章对 MyBatis 配置文件中常用配置的解析过程进行了较为详细的介绍和分析,包括但不限于settings,typeAl ...

  2. InfluxDB源码目录结构解析

    操作系统 : CentOS7.3.1611_x64 go语言版本:1.8.3 linux/amd64 InfluxDB版本:1.1.0 influxdata主目录结构 [root@localhost ...

  3. Spring源码入门——DefaultBeanNameGenerator解析 转发 https://www.cnblogs.com/jason0529/p/5272265.html

    Spring源码入门——DefaultBeanNameGenerator解析   我们知道在spring中每个bean都要有一个id或者name标示每个唯一的bean,在xml中定义一个bean可以指 ...

  4. 笔记-twisted源码-import reactor解析

    笔记-twisted源码-import reactor解析 1.      twisted源码解析-1 twisted reactor实现原理: 第一步: from twisted.internet ...

  5. 鸿蒙内核源码分析(ELF解析篇) | 你要忘了她姐俩你就不是银 | 百篇博客分析OpenHarmony源码 | v53.02

    百篇博客系列篇.本篇为: v53.xx 鸿蒙内核源码分析(ELF解析篇) | 你要忘了她姐俩你就不是银 | 51.c.h.o 加载运行相关篇为: v51.xx 鸿蒙内核源码分析(ELF格式篇) | 应 ...

  6. v72.01 鸿蒙内核源码分析(Shell解析) | 应用窥伺内核的窗口 | 百篇博客分析OpenHarmony源码

    子曰:"苟正其身矣,于从政乎何有?不能正其身,如正人何?" <论语>:子路篇 百篇博客系列篇.本篇为: v72.xx 鸿蒙内核源码分析(Shell解析篇) | 应用窥视 ...

  7. Java并发包源码学习系列:线程池ScheduledThreadPoolExecutor源码解析

    目录 ScheduledThreadPoolExecutor概述 类图结构 ScheduledExecutorService ScheduledFutureTask FutureTask schedu ...

  8. 从源码的角度解析View的事件分发

    有好多朋友问过我各种问题,比如:onTouch和onTouchEvent有什么区别,又该如何使用?为什么给ListView引入了一个滑动菜单的功能,ListView就不能滚动了?为什么图片轮播器里的图 ...

  9. ashMap源码阅读与解析

    目录结构 导入语 HashMap构造方法 put()方法解析 addEntry()方法解析 get()方法解析 remove()解析 HashMap如何进行遍历 导入语 HashMap是我们最常见也是 ...

随机推荐

  1. RFID-RC522 模块的读写操作【Arduino】

    接线 Arduino Uno <-> RFID-RC52210 <-> SDA13 <-> SCK11 <-> MOSI12 <-> MIS ...

  2. belongsTo和hasOne的区别

    简单的讲就是,没有太大的区别,只是在逻辑上出现的思想的偏差(逻辑的合理性).belongsTo:可以理解为属于hasOne:可以理解为拥有 首先,我们创建两张表.user表 字段 id name pa ...

  3. 特性速览| Apache Hudi 0.5.3版本正式发布

    1. 下载连接 源代码下载:Apache Hudi 0.5.3 Source Release (asc, sha512) 0.5.3版本相关jar包地址:https://repository.apac ...

  4. Nginx安装配置介绍(二)

    一:Nginx安装(Windows) 官网地址:https://nginx.org/en/download.html 解压完成后,文件目录如下: 启动Nginx: 直接双击目录下的nginx.exe, ...

  5. 一分钟开始持续集成之旅系列之:C 语言 + Makefile

    作者:CODING - 朱增辉 前言 make 工具非常强大,配合 makefile 文件可以实现软件的自动化构建,但是执行 make 命令依然需要经历手动输入执行.等待编译完成.将目标文件转移到合适 ...

  6. SpringMVC拦截器使用

    源码地址 拦截器interceptor 拦截器是URL请求的第一道门,所有请求会先经过拦截器interceptor,然后再进入controller: 下面,记录一种通过注解方法拦截所有需要登录才能发起 ...

  7. 【原创】Linux中断子系统(四)-Workqueue

    背景 Read the fucking source code! --By 鲁迅 A picture is worth a thousand words. --By 高尔基 说明: Kernel版本: ...

  8. .net core docker容器编排部署(linux)

    环境准备 需要一个linux操作系统:我这里用的是ubuntu 18.04,安装步骤就不说了,网上很多教程,当然也可以私信我. 既然需要用到docker,那么就安装个docker,apt instal ...

  9. Oracle 闪回总结

    一.闪回查询(Flashback Query)1.闪回查询技术1.1 闪回查询机制    闪回查询是指利用数据库回滚段存放的信息查看指定表中过去某个时间点的数据信息,或过去某个时间段数据的变化情况,或 ...

  10. Java 从入门到进阶之路(二十六)

    在之前的文章我们介绍了一下 Java 中的  集合框架中的Collection 的子接口 List,本章我们来看一下 Java 集合框架中的Collection 的子接口 Queue. 在之前我们讲 ...