java.util.concurrent

public class ScheduledThreadPoolExecutor extends ThreadPoolExecutor implements ScheduledExecutorService

简介

ScheduledThreadPoolExecutor可以在指定的时延后,调度一个任务,或间歇性地执行任务。

当需要多线程执行任务或需要的ThreadPoolExecutor的灵活性和功能性时, ScheduledThreadPoolExecutor是一个比java.util.Timer中更优的选择。

只有最先到期的任务会出队,如果没有任务或者队首任务未到期,则工作线程会阻塞;

一旦核心线程池满了,ScheduledThreadPoolExecutor不会像ThreadPoolExecutor那样再去创建归属于非核心线程池的工作线程,而是直接返回。

优点

  1. 使用多线程执行任务,不用担心任务执行时间过长而导致任务相互阻塞的情况(Timer是单线程执行的,因而会出现这个问题)
  2. 不用担心任务执行过程中,如果线程失活,其会新建线程执行任务(Timer类的单线程挂掉之后是不会重新创建线程执行后续任务的)

源码

ScheduledThreadPoolExecutor:

属性:

/**
* False if should cancel/suppress periodic tasks on shutdown.
*/
private volatile boolean continueExistingPeriodicTasksAfterShutdown; /**
* False if should cancel non-periodic not-yet-expired tasks on shutdown.
*/
private volatile boolean executeExistingDelayedTasksAfterShutdown = true; 方法: public<V> ScheduledFuture<V> schedule(Callable<V> callable,long delay,TimeUnit unit); public<V> ScheduledFuture<V> schedule(Callable<V> callable,long delay,TimeUnit unit) {
if (callable == null || unit == null)
throw new NullPointerException();
RunnableScheduledFuture<V> t = decorateTask(callable,
new ScheduledFutureTask<V>(callable,
triggerTime(delay, unit),
sequencer.getAndIncrement()));
// 延时执行任务
delayedExecute(t);
return t;
} private void delayedExecute(RunnableScheduledFuture<?> task) {
if (isShutdown())
reject(task);
else {
// 将任务添加到任务队列中,会根据任务的延时时间进行排序
super.getQueue().add(task);
if (!canRunInCurrentRunState(task) && remove(task))
task.cancel(false);
else
//预先启动工作线程,确保线程池中有工作线程。
ensurePrestart();
}
} void ensurePrestart() {
int wc = workerCountOf(ctl.get());
//如果小于核心池数量,就创建新的工作线程
if (wc < corePoolSize)
addWorker(null, true);
//说明corePoolSize数量是0,必须创建一个工作线程来执行任务
else if (wc == 0)
addWorker(null, false); //ThreadPoolExecutor的方法,用来执行线程任务
} public ScheduledFuture<?> schedule(Runnable command,long delay,TimeUnit unit); //delay:延时时间 //initialDelay:第一次延时时间;delay:周期间隔
//执行任务的间隔是固定的,无论上一个任务是否执行完成,
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
long initialDelay,long delay,TimeUnit unit); //执行时间间隔是不固定的,其会在周期任务的上一个任务执行完成之后才开始计时,并在指定时间间隔之后才开始执行任务
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
long initialDelay,long period,TimeUnit unit); ScheduledThreadPoolExecutor 内部类: private class ScheduledFutureTask<V> extends FutureTask<V> implements RunnableScheduledFuture<V> { private final long sequenceNumber; //为相同延时任务提供的顺序编号 private volatile long time; //任务可以执行的时间,纳秒级 private final long period; //重复任务的执行周期时间,纳秒级。 RunnableScheduledFuture<V> outerTask = this; //重新入队的任务 int heapIndex; //延迟队列的索引,以支持更快的取消操作 ScheduledFutureTask(Runnable r, V result, long triggerTime,
long sequenceNumber) ScheduledFutureTask(Runnable r, V result, long triggerTime,
long period, long sequenceNumber) ScheduledFutureTask(Callable<V> callable, long triggerTime,
long sequenceNumber) public void run() {
boolean periodic = isPeriodic(); //是否为周期任务
if (!canRunInCurrentRunState(periodic)) //当前状态是否可以执行
cancel(false);
else if (!periodic)
//不是周期任务,直接执行
ScheduledFutureTask.super.run();
else if (ScheduledFutureTask.super.runAndReset()) {
setNextRunTime(); //设置下一次运行时间
reExecutePeriodic(outerTask); //重排序一个周期任务
}
}
} DelayedWorkQueue 内部类: 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; /**
* Condition signalled when a newer task becomes available at the
* head of the queue or a new thread may need to become leader.
*/
private final Condition available = lock.newCondition();
}

特性

  1. 使用专门的任务类型—ScheduledFutureTask(内部类)来执行周期任务
  2. 使用专门的存储队列—DelayedWorkQueue(内部类)来存储任务,DelayedWorkQueue是无界延迟队列DelayQueue的一种。
  3. 支持可选的run-after-shutdown参数,在池被关闭(shutdown)之后支持可选的逻辑来决定是否继续运行周期或延迟任务。

ScheduledThreadPoolExecutor的关闭策略由两个run-after-shutdown参数实现,用来控制在池关闭之后是否继续执行任务:

  1. continueExistingPeriodicTasksAfterShutdown(boolean类型):表示在池关闭之后是否继续执行已经存在的周期任务
  2. executeExistingDelayedTasksAfterShutdown(boolean类型,默认true,表示继续):表示在池关闭之后是否继续执行已经存在的延迟任务

ScheduledThreadPoolExecutor 重写了 execute(Runnable) 和 submit(Runnable) 方法

    public void execute(Runnable command) {
schedule(command, 0, NANOSECONDS);
} public Future<?> submit(Runnable task) {
return schedule(task, 0, NANOSECONDS);
}

示例

public class Test {

    private ScheduledThreadPoolExecutor executor;
private Runnable task; public Test() {
this.executor = new ScheduledThreadPoolExecutor(2);
this.task = initTask();
} //延迟15s后每隔30s执行一次指定的任务,而该任务执行时长为10s。
private Runnable initTask() {
return task = () -> {
sleep(SECONDS, 10);
};
} public void testFixedTask() {
executor.scheduleAtFixedRate(task, 15, 30, SECONDS);
sleep(SECONDS, 120);
} public void testDelayedTask() {
executor.scheduleWithFixedDelay(task, 15, 30, SECONDS);
}
}

线程池 一 ScheduledThreadPoolExecutor的更多相关文章

  1. Java并发包线程池之ScheduledThreadPoolExecutor

    前言 它是一种可以安排在给定的延迟之后执行一次或周期性执行任务的ThreadPoolExecutor.因为它继承了ThreadPoolExecutor, 当然也具有处理普通Runnable.Calla ...

  2. 深入理解Java线程池:ScheduledThreadPoolExecutor

    介绍 自JDK1.5开始,JDK提供了ScheduledThreadPoolExecutor类来支持周期性任务的调度.在这之前的实现需要依靠Timer和TimerTask或者其它第三方工具来完成.但T ...

  3. 22.线程池之ScheduledThreadPoolExecutor

    1. ScheduledThreadPoolExecutor简介 ScheduledThreadPoolExecutor可以用来在给定延时后执行异步任务或者周期性执行任务,相对于任务调度的Timer来 ...

  4. 线程池之ScheduledThreadPoolExecutor线程池源码分析笔记

    1.ScheduledThreadPoolExecutor 整体结构剖析. 1.1类图介绍 根据上面类图图可以看到Executor其实是一个工具类,里面提供了好多静态方法,根据用户选择返回不同的线程池 ...

  5. ScheduledThreadPoolExecutor 使用线程池执行定时任务

    转自:https://segmentfault.com/a/1190000008038848 在现实世界里,我们总是免不了要定期去做一件事情(比如上课)—— 在计算机的世界里,更是如此.比如我们手机每 ...

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

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

  7. javase-->多线程--线程池

    java的线程池理解 在面向对象编程中,对象创建和销毁是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源.在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收. ...

  8. Java多线程之Executor框架和手写简易的线程池

    目录 Java多线程之一线程及其基本使用 Java多线程之二(Synchronized) Java多线程之三volatile与等待通知机制示例 线程池 什么是线程池 线程池一种线程使用模式,线程池会维 ...

  9. 为什么阿里Java规约禁止使用Java内置线程池?

    IDEA导入阿里规约插件,当你这样写代码时,插件就会自动监测出来,并给你红线提醒. 告诉你手动创建线程池,效果会更好. 在探秘原因之前我们要先了解一下线程池 ThreadPoolExecutor 都有 ...

随机推荐

  1. 【LeetCode】Hash

    [451] Sort Characters By Frequency [Medium] 给一个字符串,要求返回按照字母出现频率的排序后的字符串.(哈希表+桶排) 有个技巧是Hash用Value作为In ...

  2. java反射技术主要实现类有哪些,作用分别是什么

    Java反射技术主要实现类有哪些,作用分别是什么? 在JDK中,主要由以下类来实现Java反射机制,这些类都位于java.lang.reflect包中 1)Class类:代表一个类 2)Field 类 ...

  3. 【Movist Pro】macOS上的绝佳媒体播放器

    Movist Pro是适用于Mac的高性能电影播放器,如果比较流程和界面,则Movist与QuickTime非常相似.因此,采用播放器几乎不会有任何问题.使用Quicktime或FFmpeg解码电影并 ...

  4. pygame游戏框架

    #_author:来童星#date:2019/12/22 import pygame import sys pygame.init() size=width,height=640,480 screen ...

  5. Java类的成员之四:代码块.

    3.2类的成员之四:代码块 ①初始化块(代码块)作用:对Java对象进行初始化 ②程序的执行顺序: ③一个类中初始化块若有修饰符,则只能被static修饰,称为静态代码块(static block ) ...

  6. 编辑bbs文章 获取前端标题内容 和前端内容的方法

  7. Luogu P1738 洛谷的文件夹

    P1738 Luogu 发一个链表题解! 仅有24ms,排名第一哦~ 圆圈代表点,每个店有两个指针,一个指向自己兄弟(同级文件夹),另一个指向自己孩子(子文件夹),还有一个保存当前名字. 有点像二叉树 ...

  8. windows系统使用

    1.访问局域网共享的文件,用 \\ip号 2.电脑的硬件名称(设备管理器中)是可以用软件修改的. 3.电脑中每一个连接网络的设备都有一个网卡地址(MAC地址),如无线网卡地址.有线网卡地址. 4.wi ...

  9. Machine Learning 之二,什么监督性学习,非监督性学习。

    1.什么是监督性学习?Supervised  Machine Learning. 在监督性学习,我们给定一个数据集以及我们已经知道正确输出的结果,然后找到一个输入和输出的关系. In Supervis ...

  10. js基础关系运算符

    js基础关系运算符 == 是否相等(只检查值) x=5,y='-5';x==y true === 是否全等(检查值和数据类型) x=5,y='-5';x===y false != 是否不等于 5!=8 ...