ScheduledThreadPoolExecutor

  1. ScheduledThreadPoolExecutor 是能够在给定的延时之后、或周期性执行被提交任务的线程池

创建实例

  1. /**
  2. * 线程池关闭时是否需要继续执行周期性任务
  3. */
  4. private volatile boolean continueExistingPeriodicTasksAfterShutdown;
  5. /**
  6. * 线程池关闭时是否需要执行已经存在的延时任务
  7. */
  8. private volatile boolean executeExistingDelayedTasksAfterShutdown = true;
  9. /**
  10. * 执行 ScheduledFutureTask.cancel 操作时是否需要将任务从任务队列中移除
  11. */
  12. volatile boolean removeOnCancel;
  13. /**
  14. * Sequence number to break scheduling ties, and in turn to
  15. * guarantee FIFO order among tied entries.
  16. */
  17. private static final AtomicLong sequencer = new AtomicLong();
  18. /**
  19. * 默认的线程超时时间为 10 毫秒
  20. */
  21. private static final long DEFAULT_KEEPALIVE_MILLIS = 10L;
  22. public ScheduledThreadPoolExecutor(int corePoolSize) {
  23. super(corePoolSize, Integer.MAX_VALUE,
  24. DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
  25. new DelayedWorkQueue());
  26. }
  27. public ScheduledThreadPoolExecutor(int corePoolSize,
  28. ThreadFactory threadFactory) {
  29. super(corePoolSize, Integer.MAX_VALUE,
  30. DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
  31. new DelayedWorkQueue(), threadFactory);
  32. }
  33. public ScheduledThreadPoolExecutor(int corePoolSize,
  34. RejectedExecutionHandler handler) {
  35. super(corePoolSize, Integer.MAX_VALUE,
  36. DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
  37. new DelayedWorkQueue(), handler);
  38. }
  39. public ScheduledThreadPoolExecutor(int corePoolSize,
  40. ThreadFactory threadFactory,
  41. RejectedExecutionHandler handler) {
  42. super(corePoolSize, Integer.MAX_VALUE,
  43. DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
  44. new DelayedWorkQueue(), threadFactory, handler);
  45. }
  46. private class ScheduledFutureTask<V>
  47. extends FutureTask<V> implements RunnableScheduledFuture<V> {
  48. /** Sequence number to break ties FIFO */
  49. private final long sequenceNumber;
  50. /** 当前任务需要在指定的纳秒时间后执行 */
  51. private volatile long time;
  52. /**
  53. * 重复任务的执行周期,以纳秒为单位
  54. * 正数表示以 fixed-rate 模式执行
  55. * 负数表示以 fixed-delay 模式执行
  56. * 0 表示不需要重复执行
  57. */
  58. private final long period;
  59. /** 需要重新入队的周期性任务 */
  60. RunnableScheduledFuture<V> outerTask = this;
  61. /**
  62. * 当前任务在延迟队列中的索引,以支持快速删除
  63. */
  64. int heapIndex;
  65. /**
  66. * 创建一个在 triggerTime 执行的一次性任务
  67. */
  68. ScheduledFutureTask(Runnable r, V result, long triggerTime,
  69. long sequenceNumber) {
  70. super(r, result);
  71. this.time = triggerTime;
  72. this.period = 0;
  73. this.sequenceNumber = sequenceNumber;
  74. }
  75. /**
  76. * 创建一个在 triggerTime 第一次执行,并以 period 为周期的周期性任务
  77. */
  78. ScheduledFutureTask(Runnable r, V result, long triggerTime,
  79. long period, long sequenceNumber) {
  80. super(r, result);
  81. this.time = triggerTime;
  82. this.period = period;
  83. this.sequenceNumber = sequenceNumber;
  84. }
  85. /**
  86. * 创建一个在 triggerTime 执行的一次性任务
  87. */
  88. ScheduledFutureTask(Callable<V> callable, long triggerTime,
  89. long sequenceNumber) {
  90. super(callable);
  91. this.time = triggerTime;
  92. this.period = 0;
  93. this.sequenceNumber = sequenceNumber;
  94. }
  95. /**
  96. * 读取当前任务的延时时间
  97. * created by ZXD at 9 Dec 2018 T 20:40:27
  98. * @param unit
  99. * @return
  100. */
  101. @Override
  102. public long getDelay(TimeUnit unit) {
  103. return unit.convert(time - System.nanoTime(), NANOSECONDS);
  104. }
  105. /**
  106. * 当前任务是否是周期性任务
  107. */
  108. @Override
  109. public boolean isPeriodic() {
  110. return period != 0;
  111. }
  112. /**
  113. * 计算周期性任务的下一次触发时间
  114. */
  115. private void setNextRunTime() {
  116. final long p = period;
  117. if (p > 0) {
  118. // 基于上次记录的时间进行延时,可能已经超时
  119. time += p;
  120. } else {
  121. // 基于 System.nanoTime() 进行延时
  122. time = triggerTime(-p);
  123. }
  124. }
  125. /**
  126. * Overrides FutureTask version so as to reset/requeue if periodic.
  127. */
  128. @Override
  129. public void run() {
  130. // 1)当前任务是否能在线程池中执行
  131. if (!canRunInCurrentRunState(this)) {
  132. // 不能执行,则将其取消
  133. cancel(false);
  134. // 2)如果不是周期性任务
  135. } else if (!isPeriodic()) {
  136. // 则执行该任务
  137. super.run();
  138. // 3)如果是周期性任务,运行任务并且重置状态
  139. } else if (super.runAndReset()) {
  140. // 计算周期性任务的下一次触发时间
  141. setNextRunTime();
  142. // 重新将任务加入到延时队列中
  143. reExecutePeriodic(outerTask);
  144. }
  145. }
  146. }
  147. /**
  148. * 基于二叉堆实现的延迟优先级队列,队列元素只能是 RunnableScheduledFuture 实例。
  149. */
  150. static class DelayedWorkQueue extends AbstractQueue<Runnable>
  151. implements BlockingQueue<Runnable> {
  152. // 初始容量
  153. private static final int INITIAL_CAPACITY = 16;
  154. // 保持元素的数组
  155. private RunnableScheduledFuture<?>[] queue =
  156. new RunnableScheduledFuture<?>[INITIAL_CAPACITY];
  157. // 互斥锁
  158. private final ReentrantLock lock = new ReentrantLock();
  159. // 元素总数
  160. private int size;
  161. /**
  162. * 在队列头部阻塞等待任务的线程
  163. */
  164. private Thread leader;
  165. /**
  166. * 是否有任务可用
  167. */
  168. private final Condition available = lock.newCondition();
  169. }
  170. void reExecutePeriodic(RunnableScheduledFuture<?> task) {
  171. // 当前任务是否能在线程池中运行
  172. if (canRunInCurrentRunState(task)) {
  173. // 将任务加入到延时队列中
  174. super.getQueue().add(task);
  175. // 又进行一次判断,如果不能运行目标任务则尝试从延时队列中删除它
  176. if (canRunInCurrentRunState(task) || !remove(task)) {
  177. ensurePrestart();
  178. return;
  179. }
  180. }
  181. // 任务不能运行,则将其取消
  182. task.cancel(false);
  183. }

延时执行一次性任务

  1. /**
  2. * 在指定的延时后执行目标任务
  3. */
  4. @Override
  5. public ScheduledFuture<?> schedule(Runnable command,
  6. long delay,
  7. TimeUnit unit) {
  8. if (command == null || unit == null) {
  9. throw new NullPointerException();
  10. }
  11. // 创建一个单次延时任务
  12. final RunnableScheduledFuture<Void> t = decorateTask(command,
  13. new ScheduledFutureTask<Void>(command, null,
  14. triggerTime(delay, unit),
  15. sequencer.getAndIncrement()));
  16. // 加入延时队列中执行
  17. delayedExecute(t);
  18. return t;
  19. }
  20. private void delayedExecute(RunnableScheduledFuture<?> task) {
  21. // 线程池处于 SHUTDOWN 及以上状态
  22. if (isShutdown()) {
  23. // 拒绝执行任务
  24. reject(task);
  25. } else {
  26. // 将任务加入延时优先级队列
  27. super.getQueue().add(task);
  28. /**
  29. * 当前任务不能执行 && 将其从延时队列中移除成功
  30. */
  31. if (!canRunInCurrentRunState(task) && remove(task)) {
  32. // 则取消该任务
  33. task.cancel(false);
  34. } else {
  35. /**
  36. * 尝试启动一个工作者线程来处理延时任务
  37. * 1)当前工作者线程 < 核心线程数
  38. * 2)当前工作者线程 == 0
  39. */
  40. ensurePrestart();
  41. }
  42. }
  43. }
  44. /**
  45. * 是否能在当前线程池状态下运行
  46. */
  47. boolean canRunInCurrentRunState(RunnableScheduledFuture<?> task) {
  48. // 线程池处于 RUNNING 状态,则允许运行
  49. if (!isShutdown()) {
  50. return true;
  51. }
  52. // 线程池已经停止,则不允许运行
  53. if (isStopped()) {
  54. return false;
  55. }
  56. /**
  57. * 线程池处于 SHUTDOWN 状态正在停止
  58. * 1)当前任务是周期任务,continueExistingPeriodicTasksAfterShutdown 默认为 false
  59. * 2)当前任务是一次性任务,executeExistingDelayedTasksAfterShutdown 默认为 false
  60. * 如果任务已经超时,则执行它。
  61. */
  62. return task.isPeriodic()
  63. ? continueExistingPeriodicTasksAfterShutdown
  64. : executeExistingDelayedTasksAfterShutdown
  65. || task.getDelay(NANOSECONDS) <= 0;
  66. }
  67. /**
  68. * 尝试启动一个工作者线程来处理延时任务
  69. */
  70. void ensurePrestart() {
  71. final int wc = ThreadPoolExecutor.workerCountOf(ctl.get());
  72. if (wc < corePoolSize) {
  73. addWorker(null, true);
  74. } else if (wc == 0) {
  75. addWorker(null, false);
  76. }
  77. }

延时执行周期性任务

  • 在以 unit 为单位的 initialDelay 延时后执行第一次任务,

    并在 initialDelay + period,initialDelay + 2 * period 等时间点周期性执行。

    如果任务执行时间超出 period,则下次任务会立即开始执行。
  1. /**
  2. * 在以 unit 为单位的 initialDelay 延时后执行第一次任务,并在
  3. * initialDelay + period,initialDelay + 2 * period 等时间点周期性执行
  4. */
  5. @Override
  6. public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
  7. long initialDelay,
  8. long period,
  9. TimeUnit unit) {
  10. // 任务和时间单位不能为 null
  11. if (command == null || unit == null) {
  12. throw new NullPointerException();
  13. }
  14. // 执行周期必须 > 0
  15. if (period <= 0L) {
  16. throw new IllegalArgumentException();
  17. }
  18. final ScheduledFutureTask<Void> sft =
  19. new ScheduledFutureTask<>(command,
  20. null,
  21. triggerTime(initialDelay, unit),
  22. unit.toNanos(period),
  23. sequencer.getAndIncrement());
  24. final RunnableScheduledFuture<Void> t = decorateTask(command, sft);
  25. sft.outerTask = t;
  26. delayedExecute(t);
  27. return t;
  28. }
  • 在以 unit 为单位的 initialDelay 延时后执行第一次任务,

    并在当次任务执行完成之后在 delay 延时之后再次执行。
  1. /**
  2. * 在以 unit 为单位的 initialDelay 延时后执行第一次任务,并在当次任务执行完成之后
  3. * 在 delay 延时之后再次执行。
  4. */
  5. @Override
  6. public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
  7. long initialDelay,
  8. long delay,
  9. TimeUnit unit) {
  10. if (command == null || unit == null) {
  11. throw new NullPointerException();
  12. }
  13. if (delay <= 0L) {
  14. throw new IllegalArgumentException();
  15. }
  16. final ScheduledFutureTask<Void> sft =
  17. new ScheduledFutureTask<>(command,
  18. null,
  19. triggerTime(initialDelay, unit),
  20. -unit.toNanos(delay),
  21. sequencer.getAndIncrement());
  22. final RunnableScheduledFuture<Void> t = decorateTask(command, sft);
  23. sft.outerTask = t;
  24. delayedExecute(t);
  25. return t;
  26. }

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

  1. ScheduledThreadPoolExecutor源码分析-你知道定时线程池是如何实现延迟执行和周期执行的吗?

    Java版本:8u261. 1 简介 ScheduledThreadPoolExecutor即定时线程池,是用来执行延迟任务或周期性任务的.相比于Timer的单线程,定时线程池在遇到任务抛出异常的时候 ...

  2. Java调度线程池ScheduledThreadPoolExecutor源码分析

    最近新接手的项目里大量使用了ScheduledThreadPoolExecutor类去执行一些定时任务,之前一直没有机会研究这个类的源码,这次趁着机会好好研读一下. 该类主要还是基于ThreadPoo ...

  3. JUC源码分析-线程池篇(三)ScheduledThreadPoolExecutor

    JUC源码分析-线程池篇(三)ScheduledThreadPoolExecutor ScheduledThreadPoolExecutor 继承自 ThreadPoolExecutor.它主要用来在 ...

  4. 线程池底层原理详解与源码分析(补充部分---ScheduledThreadPoolExecutor类分析)

    [1]前言 本篇幅是对 线程池底层原理详解与源码分析  的补充,默认你已经看完了上一篇对ThreadPoolExecutor类有了足够的了解. [2]ScheduledThreadPoolExecut ...

  5. 【JUC】JDK1.8源码分析之ThreadPoolExecutor(一)

    一.前言 JUC这部分还有线程池这一块没有分析,需要抓紧时间分析,下面开始ThreadPoolExecutor,其是线程池的基础,分析完了这个类会简化之后的分析,线程池可以解决两个不同问题:由于减少了 ...

  6. 死磕 java集合之DelayQueue源码分析

    问题 (1)DelayQueue是阻塞队列吗? (2)DelayQueue的实现方式? (3)DelayQueue主要用于什么场景? 简介 DelayQueue是java并发包下的延时阻塞队列,常用于 ...

  7. JDK源码分析(9)之 WeakHashMap 相关

    平时我们使用最多的数据结构肯定是 HashMap,但是在使用的时候我们必须知道每个键值对的生命周期,并且手动清除它:但是如果我们不是很清楚它的生命周期,这时候就比较麻烦:通常有这样几种处理方式: 由一 ...

  8. Dubbo 源码分析 - 服务调用过程

    注: 本系列文章已捐赠给 Dubbo 社区,你也可以在 Dubbo 官方文档中阅读本系列文章. 1. 简介 在前面的文章中,我们分析了 Dubbo SPI.服务导出与引入.以及集群容错方面的代码.经过 ...

  9. ScheduledThreadPoolExecutor源码解读

    1. 背景 在之前的博文--ThreadPoolExecutor源码解读已经对ThreadPoolExecutor的实现原理与源码进行了分析.ScheduledExecutorService也是我们在 ...

随机推荐

  1. 【源码解读】cycleGAN(三):数据读取

    源码地址:https://github.com/aitorzip/PyTorch-CycleGAN 数据的读取是比较简单的,cycleGAN对数据没有pair的需求,不同域的两个数据集分别存放于A,B ...

  2. thinkphp5 隐藏前台入口文件index.php 后台入口文件admin.php不隐藏

    情景:应用目录下有两个模块 admin(后台) 和 home(前台) 需求:1.访问前台(home)时隐藏index.php  即 域名/home/前台控制器/前台控制器里的方法 这样的访问模式 2. ...

  3. 模拟select下拉框、复选框效果

    <!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>& ...

  4. MySQl查询语句大全

    综合使用 查询 目录: #----综合使用 书写顺序 select distinct * from '表名' where '限制条件' group by '分组依据' having '过滤条件' or ...

  5. Nginx1.3.15导致Wordpress,Drupal等框架无限重定向的解决方案

    Wordpress建立的站点出现无限循环重定向问题.很多人遇到这个问题,并不是单纯Wordpress,Drupal, PHPCake等框架也都遇到同样的问题. 新版本的Nginx在收到 http:// ...

  6. CentOS7搭建FastDFS V5.11分布式文件系统及Java整合详细过程

    1.1 FastDFS的应用场景 FastDFS是为互联网应用量身定做的一套分布式文件存储系统,非常适合用来存储用户图片.视频.文档等文件.对于互联网应用,和其他分布式文件系统相比,优势非常明显.其中 ...

  7. IP电话的配置

    内容描述:IP电话配置 问题描述: IP电话站点为8203,IP地址为10.11.6.3,电话状态为空心(不正常). 处理过程: 1.在浏览器中打开输入原先已经配置正常的IP话机的IP地址访问其配置, ...

  8. vue简单插件

    已经很久没有学习新的相关知识,对于今后的学习方向可能会集中在vue的源码,render,jsx语法,服务端渲染来学习,巩固好vue的基础和高级的知识,现阶段vue的api和基本用法已经全部掌握,但是还 ...

  9. jmeter性能压测瓶颈排查-网络带宽

    问题: 有一台机器做性能压测的时候,无论开多少个线程,QPS一直压不上去,而服务器和数据库的性能指标(主要是CPU和内存)一直维持在很低的水平. 希望帮忙排查一下原因. 过去看了下进行压测的接口代码, ...

  10. [易学易懂系列|golang语言|零基础|快速入门|(三)]

    接下来,我们主要讲讲package. 先列举下go的package的一些核心特性: 1.go的package不局限于一个文件,组成一个package的多个文件,编译后实际上和一个文件类似,组成包的不同 ...