ScheduledThreadPoolExecutor 源码分析
ScheduledThreadPoolExecutor
ScheduledThreadPoolExecutor 是能够在给定的延时之后、或周期性执行被提交任务的线程池
创建实例
/**
* 线程池关闭时是否需要继续执行周期性任务
*/
private volatile boolean continueExistingPeriodicTasksAfterShutdown;
/**
* 线程池关闭时是否需要执行已经存在的延时任务
*/
private volatile boolean executeExistingDelayedTasksAfterShutdown = true;
/**
* 执行 ScheduledFutureTask.cancel 操作时是否需要将任务从任务队列中移除
*/
volatile boolean removeOnCancel;
/**
* Sequence number to break scheduling ties, and in turn to
* guarantee FIFO order among tied entries.
*/
private static final AtomicLong sequencer = new AtomicLong();
/**
* 默认的线程超时时间为 10 毫秒
*/
private static final long DEFAULT_KEEPALIVE_MILLIS = 10L;
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE,
DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
new DelayedWorkQueue());
}
public ScheduledThreadPoolExecutor(int corePoolSize,
ThreadFactory threadFactory) {
super(corePoolSize, Integer.MAX_VALUE,
DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
new DelayedWorkQueue(), threadFactory);
}
public ScheduledThreadPoolExecutor(int corePoolSize,
RejectedExecutionHandler handler) {
super(corePoolSize, Integer.MAX_VALUE,
DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
new DelayedWorkQueue(), handler);
}
public ScheduledThreadPoolExecutor(int corePoolSize,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
super(corePoolSize, Integer.MAX_VALUE,
DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
new DelayedWorkQueue(), threadFactory, handler);
}
private class ScheduledFutureTask<V>
extends FutureTask<V> implements RunnableScheduledFuture<V> {
/** Sequence number to break ties FIFO */
private final long sequenceNumber;
/** 当前任务需要在指定的纳秒时间后执行 */
private volatile long time;
/**
* 重复任务的执行周期,以纳秒为单位
* 正数表示以 fixed-rate 模式执行
* 负数表示以 fixed-delay 模式执行
* 0 表示不需要重复执行
*/
private final long period;
/** 需要重新入队的周期性任务 */
RunnableScheduledFuture<V> outerTask = this;
/**
* 当前任务在延迟队列中的索引,以支持快速删除
*/
int heapIndex;
/**
* 创建一个在 triggerTime 执行的一次性任务
*/
ScheduledFutureTask(Runnable r, V result, long triggerTime,
long sequenceNumber) {
super(r, result);
this.time = triggerTime;
this.period = 0;
this.sequenceNumber = sequenceNumber;
}
/**
* 创建一个在 triggerTime 第一次执行,并以 period 为周期的周期性任务
*/
ScheduledFutureTask(Runnable r, V result, long triggerTime,
long period, long sequenceNumber) {
super(r, result);
this.time = triggerTime;
this.period = period;
this.sequenceNumber = sequenceNumber;
}
/**
* 创建一个在 triggerTime 执行的一次性任务
*/
ScheduledFutureTask(Callable<V> callable, long triggerTime,
long sequenceNumber) {
super(callable);
this.time = triggerTime;
this.period = 0;
this.sequenceNumber = sequenceNumber;
}
/**
* 读取当前任务的延时时间
* created by ZXD at 9 Dec 2018 T 20:40:27
* @param unit
* @return
*/
@Override
public long getDelay(TimeUnit unit) {
return unit.convert(time - System.nanoTime(), NANOSECONDS);
}
/**
* 当前任务是否是周期性任务
*/
@Override
public boolean isPeriodic() {
return period != 0;
}
/**
* 计算周期性任务的下一次触发时间
*/
private void setNextRunTime() {
final long p = period;
if (p > 0) {
// 基于上次记录的时间进行延时,可能已经超时
time += p;
} else {
// 基于 System.nanoTime() 进行延时
time = triggerTime(-p);
}
}
/**
* Overrides FutureTask version so as to reset/requeue if periodic.
*/
@Override
public void run() {
// 1)当前任务是否能在线程池中执行
if (!canRunInCurrentRunState(this)) {
// 不能执行,则将其取消
cancel(false);
// 2)如果不是周期性任务
} else if (!isPeriodic()) {
// 则执行该任务
super.run();
// 3)如果是周期性任务,运行任务并且重置状态
} else if (super.runAndReset()) {
// 计算周期性任务的下一次触发时间
setNextRunTime();
// 重新将任务加入到延时队列中
reExecutePeriodic(outerTask);
}
}
}
/**
* 基于二叉堆实现的延迟优先级队列,队列元素只能是 RunnableScheduledFuture 实例。
*/
static class DelayedWorkQueue extends AbstractQueue<Runnable>
implements BlockingQueue<Runnable> {
// 初始容量
private static final int INITIAL_CAPACITY = 16;
// 保持元素的数组
private RunnableScheduledFuture<?>[] queue =
new RunnableScheduledFuture<?>[INITIAL_CAPACITY];
// 互斥锁
private final ReentrantLock lock = new ReentrantLock();
// 元素总数
private int size;
/**
* 在队列头部阻塞等待任务的线程
*/
private Thread leader;
/**
* 是否有任务可用
*/
private final Condition available = lock.newCondition();
}
void reExecutePeriodic(RunnableScheduledFuture<?> task) {
// 当前任务是否能在线程池中运行
if (canRunInCurrentRunState(task)) {
// 将任务加入到延时队列中
super.getQueue().add(task);
// 又进行一次判断,如果不能运行目标任务则尝试从延时队列中删除它
if (canRunInCurrentRunState(task) || !remove(task)) {
ensurePrestart();
return;
}
}
// 任务不能运行,则将其取消
task.cancel(false);
}
延时执行一次性任务
/**
* 在指定的延时后执行目标任务
*/
@Override
public ScheduledFuture<?> schedule(Runnable command,
long delay,
TimeUnit unit) {
if (command == null || unit == null) {
throw new NullPointerException();
}
// 创建一个单次延时任务
final RunnableScheduledFuture<Void> t = decorateTask(command,
new ScheduledFutureTask<Void>(command, null,
triggerTime(delay, unit),
sequencer.getAndIncrement()));
// 加入延时队列中执行
delayedExecute(t);
return t;
}
private void delayedExecute(RunnableScheduledFuture<?> task) {
// 线程池处于 SHUTDOWN 及以上状态
if (isShutdown()) {
// 拒绝执行任务
reject(task);
} else {
// 将任务加入延时优先级队列
super.getQueue().add(task);
/**
* 当前任务不能执行 && 将其从延时队列中移除成功
*/
if (!canRunInCurrentRunState(task) && remove(task)) {
// 则取消该任务
task.cancel(false);
} else {
/**
* 尝试启动一个工作者线程来处理延时任务
* 1)当前工作者线程 < 核心线程数
* 2)当前工作者线程 == 0
*/
ensurePrestart();
}
}
}
/**
* 是否能在当前线程池状态下运行
*/
boolean canRunInCurrentRunState(RunnableScheduledFuture<?> task) {
// 线程池处于 RUNNING 状态,则允许运行
if (!isShutdown()) {
return true;
}
// 线程池已经停止,则不允许运行
if (isStopped()) {
return false;
}
/**
* 线程池处于 SHUTDOWN 状态正在停止
* 1)当前任务是周期任务,continueExistingPeriodicTasksAfterShutdown 默认为 false
* 2)当前任务是一次性任务,executeExistingDelayedTasksAfterShutdown 默认为 false
* 如果任务已经超时,则执行它。
*/
return task.isPeriodic()
? continueExistingPeriodicTasksAfterShutdown
: executeExistingDelayedTasksAfterShutdown
|| task.getDelay(NANOSECONDS) <= 0;
}
/**
* 尝试启动一个工作者线程来处理延时任务
*/
void ensurePrestart() {
final int wc = ThreadPoolExecutor.workerCountOf(ctl.get());
if (wc < corePoolSize) {
addWorker(null, true);
} else if (wc == 0) {
addWorker(null, false);
}
}
延时执行周期性任务
- 在以 unit 为单位的 initialDelay 延时后执行第一次任务,
并在 initialDelay + period,initialDelay + 2 * period 等时间点周期性执行。
如果任务执行时间超出 period,则下次任务会立即开始执行。
/**
* 在以 unit 为单位的 initialDelay 延时后执行第一次任务,并在
* initialDelay + period,initialDelay + 2 * period 等时间点周期性执行
*/
@Override
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
long initialDelay,
long period,
TimeUnit unit) {
// 任务和时间单位不能为 null
if (command == null || unit == null) {
throw new NullPointerException();
}
// 执行周期必须 > 0
if (period <= 0L) {
throw new IllegalArgumentException();
}
final ScheduledFutureTask<Void> sft =
new ScheduledFutureTask<>(command,
null,
triggerTime(initialDelay, unit),
unit.toNanos(period),
sequencer.getAndIncrement());
final RunnableScheduledFuture<Void> t = decorateTask(command, sft);
sft.outerTask = t;
delayedExecute(t);
return t;
}
- 在以 unit 为单位的 initialDelay 延时后执行第一次任务,
并在当次任务执行完成之后在 delay 延时之后再次执行。
/**
* 在以 unit 为单位的 initialDelay 延时后执行第一次任务,并在当次任务执行完成之后
* 在 delay 延时之后再次执行。
*/
@Override
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
long initialDelay,
long delay,
TimeUnit unit) {
if (command == null || unit == null) {
throw new NullPointerException();
}
if (delay <= 0L) {
throw new IllegalArgumentException();
}
final ScheduledFutureTask<Void> sft =
new ScheduledFutureTask<>(command,
null,
triggerTime(initialDelay, unit),
-unit.toNanos(delay),
sequencer.getAndIncrement());
final RunnableScheduledFuture<Void> t = decorateTask(command, sft);
sft.outerTask = t;
delayedExecute(t);
return t;
}
ScheduledThreadPoolExecutor 源码分析的更多相关文章
- ScheduledThreadPoolExecutor源码分析-你知道定时线程池是如何实现延迟执行和周期执行的吗?
Java版本:8u261. 1 简介 ScheduledThreadPoolExecutor即定时线程池,是用来执行延迟任务或周期性任务的.相比于Timer的单线程,定时线程池在遇到任务抛出异常的时候 ...
- Java调度线程池ScheduledThreadPoolExecutor源码分析
最近新接手的项目里大量使用了ScheduledThreadPoolExecutor类去执行一些定时任务,之前一直没有机会研究这个类的源码,这次趁着机会好好研读一下. 该类主要还是基于ThreadPoo ...
- JUC源码分析-线程池篇(三)ScheduledThreadPoolExecutor
JUC源码分析-线程池篇(三)ScheduledThreadPoolExecutor ScheduledThreadPoolExecutor 继承自 ThreadPoolExecutor.它主要用来在 ...
- 线程池底层原理详解与源码分析(补充部分---ScheduledThreadPoolExecutor类分析)
[1]前言 本篇幅是对 线程池底层原理详解与源码分析 的补充,默认你已经看完了上一篇对ThreadPoolExecutor类有了足够的了解. [2]ScheduledThreadPoolExecut ...
- 【JUC】JDK1.8源码分析之ThreadPoolExecutor(一)
一.前言 JUC这部分还有线程池这一块没有分析,需要抓紧时间分析,下面开始ThreadPoolExecutor,其是线程池的基础,分析完了这个类会简化之后的分析,线程池可以解决两个不同问题:由于减少了 ...
- 死磕 java集合之DelayQueue源码分析
问题 (1)DelayQueue是阻塞队列吗? (2)DelayQueue的实现方式? (3)DelayQueue主要用于什么场景? 简介 DelayQueue是java并发包下的延时阻塞队列,常用于 ...
- JDK源码分析(9)之 WeakHashMap 相关
平时我们使用最多的数据结构肯定是 HashMap,但是在使用的时候我们必须知道每个键值对的生命周期,并且手动清除它:但是如果我们不是很清楚它的生命周期,这时候就比较麻烦:通常有这样几种处理方式: 由一 ...
- Dubbo 源码分析 - 服务调用过程
注: 本系列文章已捐赠给 Dubbo 社区,你也可以在 Dubbo 官方文档中阅读本系列文章. 1. 简介 在前面的文章中,我们分析了 Dubbo SPI.服务导出与引入.以及集群容错方面的代码.经过 ...
- ScheduledThreadPoolExecutor源码解读
1. 背景 在之前的博文--ThreadPoolExecutor源码解读已经对ThreadPoolExecutor的实现原理与源码进行了分析.ScheduledExecutorService也是我们在 ...
随机推荐
- Redis的配置与数据类型
redis window系统的redis是微软团队根据官方的linux版本高仿的 官方原版: https://redis.io/ 中文官网:http://www.redis.cn 1. redis下载 ...
- tensorflow学习笔记六----------神经网络
使用mnist数据集进行神经网络的构建 import numpy as np import tensorflow as tf import matplotlib.pyplot as plt from ...
- PythonDay07
第七章 今日内容 基础数据类型补充 以后会遇到的坑 二次编码 基础类型补充 stra = "One two"print(a.capitalize()) # 首字母大写print ...
- Delphi主消息循环研究(Application.Run和Application.Initialize执行后的情况)
Application.Initialize; Application.CreateForm(TForm1, Form1); Application.Run; 第一步,貌似什么都不做,但如果提前定义I ...
- mac chromedriver error
问题一:MAC 使用splinter error Traceback (most recent call last): from splinter.browser import Browser b = ...
- Apache 的 bin 目录文件详解
[root@Apache bin]# tree ├── ab #Apache 性能测试工具 ├── apachectl #Apache 启动命令,它是一个脚本 ├── apr-1-conf ...
- Linux学习--第六天--软件包
yum在线管理 管理的是rpm包,光盘里面都有 /etc/yum.repos.d下面有四个文件,对应网络yum源,光盘yum源等.如果需要用到哪个源,将其他三个源的enabled设置为0即可. |源配 ...
- vi文本编辑器的使用
1.1.模式 编辑模式 输入模式 末行模式 1.2.常用命令 vi file 直接打开,不能修改,光标在行首 vi +n file 直接打开,不能修改,光标在第n行 vi + file 直接打开,不能 ...
- vb6中word编程总结
1,在project\references 中加入microsoft word 9.0 object library 2, 启动word Dim wApp As Word.Application ...
- Linux日常之Ubuntu系统中sendmail的安装、配置、发送邮件
一. 安装 1. sendmail必须先要安装两个包 (1)sudo apt-get install sendmail (2)sudo apt-get install sendmail-cf 2. u ...