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. 深度解密 Go 语言之 sync.map

    工作中,经常会碰到并发读写 map 而造成 panic 的情况,为什么在并发读写的时候,会 panic 呢?因为在并发读写的情况下,map 里的数据会被写乱,之后就是 Garbage in, garb ...

  2. 怎样在LaTeX中使用中文

    因为疫情在家中上课,作业提交都必须使用PDF.反正时间充裕,不如趁机回顾一下LaTeX的使用. 之前一直用的是Vimtex,但是感觉还是不太方便,于是改用了Texpad.Texpad的强大之处在于它支 ...

  3. fatal error C1083: Cannot open include file: '_defs.h': No such file or directory

    b-PAC SDK: https://www.baidu.com/link?url=p6FcG0fvFl6XJf9QdSFLBP16eaS03jOQsdr0zd8cYprHWwqVy5t53bzMrA ...

  4. IDEA自定义类注释和方法注释(自定义groovyScript方法实现多行参数注释)

    一.类注释 1.打开设置面板:file -> setting -> Editor -> file and code Templates 选择其中的inclues选项卡,并选择File ...

  5. disruptor架构三 使用场景 使用WorkHandler和BatchEventProcessor辅助创建消费者

    在helloWorld的实例中,我们创建Disruptor实例,然后调用getRingBuffer方法去获取RingBuffer,其实在很多时候,我们可以直接使用RingBuffer,以及其他的API ...

  6. urllib库使用方法

    这周打算把学过的内容重新总结一下,便于以后翻阅查找资料. urllib库是python的内置库,不需要单独下载.其主要分为四个模块: 1.urllib.request——请求模块 2.urllib.e ...

  7. webpack4.X + react-router 路由跳转

    webpack4.X  react-router 环境准备工作:windows7.webStorm 2017.1.4.Nodejs 8.7.0.npm 5.4.2 PS:安装的时我们都带上版本,这样即 ...

  8. 浅谈bfs

    广搜(bfs) 定义 广度优先算法,简称BFS.是一种图形搜索演算法,简单的说,BFS是从根节点开始,沿着树的宽度遍历树的节点,如果发现目标,终止. 与dfs的相似之处与不同 结合深搜理解 相同点:都 ...

  9. 题解 P1144 【最短路计数】

    这道题用一次SPFA就可以过了.在求最短路的同时,对答案进行统计即可. 实现: \(dis_i\)表示从1到\(i\)的最短路(实在还是不懂的话看程序吧). 当\(dis_i>dis_j+1\) ...

  10. JAVA设计模式 4【创建型】理解建造者模式

    Hello,又是拖了几天更,实在是忙的要死,有时候忙累了,真的就是倒头睡的那种,刚好今天闲下来了.今天来更新一篇建造者模式. 其实建造者模式,我们已经在上一节已经有了解过了.只不过是上一节没有提到这样 ...