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也是我们在 ...
随机推荐
- 【源码解读】cycleGAN(三):数据读取
源码地址:https://github.com/aitorzip/PyTorch-CycleGAN 数据的读取是比较简单的,cycleGAN对数据没有pair的需求,不同域的两个数据集分别存放于A,B ...
- thinkphp5 隐藏前台入口文件index.php 后台入口文件admin.php不隐藏
情景:应用目录下有两个模块 admin(后台) 和 home(前台) 需求:1.访问前台(home)时隐藏index.php 即 域名/home/前台控制器/前台控制器里的方法 这样的访问模式 2. ...
- 模拟select下拉框、复选框效果
<!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title>& ...
- MySQl查询语句大全
综合使用 查询 目录: #----综合使用 书写顺序 select distinct * from '表名' where '限制条件' group by '分组依据' having '过滤条件' or ...
- Nginx1.3.15导致Wordpress,Drupal等框架无限重定向的解决方案
Wordpress建立的站点出现无限循环重定向问题.很多人遇到这个问题,并不是单纯Wordpress,Drupal, PHPCake等框架也都遇到同样的问题. 新版本的Nginx在收到 http:// ...
- CentOS7搭建FastDFS V5.11分布式文件系统及Java整合详细过程
1.1 FastDFS的应用场景 FastDFS是为互联网应用量身定做的一套分布式文件存储系统,非常适合用来存储用户图片.视频.文档等文件.对于互联网应用,和其他分布式文件系统相比,优势非常明显.其中 ...
- IP电话的配置
内容描述:IP电话配置 问题描述: IP电话站点为8203,IP地址为10.11.6.3,电话状态为空心(不正常). 处理过程: 1.在浏览器中打开输入原先已经配置正常的IP话机的IP地址访问其配置, ...
- vue简单插件
已经很久没有学习新的相关知识,对于今后的学习方向可能会集中在vue的源码,render,jsx语法,服务端渲染来学习,巩固好vue的基础和高级的知识,现阶段vue的api和基本用法已经全部掌握,但是还 ...
- jmeter性能压测瓶颈排查-网络带宽
问题: 有一台机器做性能压测的时候,无论开多少个线程,QPS一直压不上去,而服务器和数据库的性能指标(主要是CPU和内存)一直维持在很低的水平. 希望帮忙排查一下原因. 过去看了下进行压测的接口代码, ...
- [易学易懂系列|golang语言|零基础|快速入门|(三)]
接下来,我们主要讲讲package. 先列举下go的package的一些核心特性: 1.go的package不局限于一个文件,组成一个package的多个文件,编译后实际上和一个文件类似,组成包的不同 ...