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. linux配置SVN服务

    在linux下配置SVN库,网上找到不少教程,但是对于有几个容易混淆的地方需要记录下, 1.在创建SVN文档库的时候,需要使用svn命令先创建出来, svnadmin create /home/svn ...

  2. 精美图文讲解Java AQS 共享式获取同步状态以及Semaphore的应用

    | 好看请赞,养成习惯 你有一个思想,我有一个思想,我们交换后,一个人就有两个思想 If you can NOT explain it simply, you do NOT understand it ...

  3. 【Python爬虫】HTTP基础和urllib库、requests库的使用

    引言: 一个网络爬虫的编写主要可以分为三个部分: 1.获取网页 2.提取信息 3.分析信息 本文主要介绍第一部分,如何用Python内置的库urllib和第三方库requests库来完成网页的获取.阅 ...

  4. Spring事务方法上增加synchronized真的有效果吗?

    此文转载,Spring事务本身是一个非常复制的问题,再加上线程并发处理就更加要主要了,由于再开发中有很多朋友会范与下文同样的错误,因分享给大家. 前言 Spring事务的一个奇怪的问题. 朋友问了我一 ...

  5. java 中的 自定义viewUtils框架

    在前面学习的基础上,我们自己编写一个ViewUtils注解框架类,不清楚的原理看前面的源代码 package im.weiyuan.com.viewutils; import android.supp ...

  6. C++核心内容和机制

    备注:不局限与C++版本   一. 基础知识 数据类型和POD/Trivial 数据类型: 类型转换: NULL和nullptr: 操作符重载: 全局静态变量和成员静态变量的申明和初始化: 左值和右值 ...

  7. ECSHOP 2.5.1 二次开发文档【文件结构说明和数据库表分析】

    ecshop文件架构说明 /* ECShop 2.5.1 的结构图及各文件相应功能介绍 ECShop2.5.1_Beta upload 的目录 ┣ activity.php 活动列表 ┣ affich ...

  8. Flask02-Template

    ## 基础使用 $ vim app/templates/index.html > <html> > <head> > <title>{{title ...

  9. Spring Aware介绍

    读完这篇文章你将会收获到 Aware 的使用和介绍 BeanFactoryAware 的触发时机 ApplicationContextAware 的触发时机以及它通过扩展 BeanPostProces ...

  10. 「区间DP」「洛谷P3205」「 [HNOI2010]」合唱队

    洛谷P3205 [HNOI2010]合唱队 题目: 题目描述 为了在即将到来的晚会上有更好的演出效果,作为 A 合唱队负责人的小 A 需要将合唱队的人根据他们的身高排出一个队形.假定合唱队一共 n 个 ...