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 源码分析的更多相关文章

  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. [LeetCode] 52. N皇后 II

    题目链接 : https://leetcode-cn.com/problems/n-queens-ii/ 题目描述: n 皇后问题研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间 ...

  2. npm publish 失败可能的原因记录

    npm 发布个人包时,遇到不少坑,总结如下(可能不全): 1.npm版本过低,处理:npm install -g npm update 2.可能权限原因,处理:npm publish --access ...

  3. CPM、CPC、CPA、PFP、CPS、CPL、CPR等广告术语是什么意思

    CPM.CPC.CPA.PFP.CPS.CPL.CPR等广告术语是什么意思 一个网络媒体(网站)会包含有数十个甚至成千上万个页面,网络广告所投放的位置和价格 就牵涉到特定的页面以及浏览人数的多寡.这好 ...

  4. Django基础命令

    创建工程 django-admin startproject 项目名创建应用 django-admin startapp 应用名 生成迁移 python3 manage.py makemigratio ...

  5. 十一、Boostrap-X-editable

    一.官网 http://vitalets.github.io/x-editable/index.html 二.实践 在jQuery中ajax配置项中的使用type与method的区别: type 和m ...

  6. 不启动或进入虚拟机,查看 KVM 虚拟机中的网卡信息

    #!bin/bash#作者:liusingbon#功能:#脚本使用工具guestmount,可以将虚拟机的磁盘系统挂载到真实机文件系统中#Centos7.2中安装libguestfs-tools-c, ...

  7. Schedule HDU - 6180 (multiset , 贪心)

    There are N schedules, the i-th schedule has start time si and end time ei (1 <= i <= N). Ther ...

  8. python字典总结

    今天总结一篇关于字典的知识点> 字典也是python提供的一种常用的数据结构,它用于存放具有映射关系的数据 比如成绩表,语文:34,数学:99,如果单纯的使用两个列表保存这组数据,则无法记录两组 ...

  9. python基础练习题1

    深深感知python基础是有多么重要,Ljh说一定要多练题,so,我现在开始要每天打卡练习python.加油! 01:求‘1-100’的偶数和 #第一种解法: sum=0 num=0 while nu ...

  10. mac+react-native环境搭建

    主要参考 https://reactnative.cn/docs/getting-started.html react-native中文网 IOS版 1.Node v10以上.Watchman 和 R ...