JUC-并发编程19-定时任务定时线程池-ScheduledThreadPoolExecutor

1、结构图

2、初识

ScheduledThreadPoolExecutor用来处理延时任务或定时任务。 流程如下:

2.1 定时任务分为四种 如下:

  1. 未来执行一次的任务,无返回值;

  2. 未来执行一次的任务,有返回值;

  3. 未来按固定频率重复执行的任务;

  4. 未来按固定延时重复执行的任务;

2.1.1 第一种与第二种差不多,如就是一个是有返回值,一个没有,以有返回值为例:

public class ScheduledThreadPoolExecutorTest {public static void main(String[] args) throws ExecutionException, InterruptedException {ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(10);ScheduledFuture<String> schedule = executor.schedule(() -> {return getUp("hello world");}, 3000, TimeUnit.MILLISECONDS);System.out.println("主线程无须等待。。。");System.out.println("====获取定时线程池执行结果"+schedule.get());}public static String getUp(String s){System.out.println("等待三秒后返回");return s.toUpperCase();}/*public static void setUp(String s){System.out.println("等待三秒后返回");System.out.println(s.toUpperCase());}*/
}

2.1.2 scheduleAtFixedRate()方法

按照固定频率重复执行的任务

示例代码如下:

public class ScheduledThreadPoolExecutorTest {public static void main(String[] args) throws ExecutionException, InterruptedException {ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(10)executor.scheduleAtFixedRate(() -> {System.out.println("hello world");},1,2,TimeUnit.SECONDS);}
}

scheduleAtFixedRate方法如下:

public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit) {if (command == null || unit == null)throw new NullPointerException();if (period <= 0)throw new IllegalArgumentException();// 将普通任务装饰成ScheduledFutureTaskScheduledFutureTask<Void> sft =new ScheduledFutureTask<Void>(command,null,triggerTime(initialDelay, unit),unit.toNanos(period));// 钩子方法,给子类用来替换装饰task,这里认为t==sftRunnableScheduledFuture<Void> t = decorateTask(command, sft);sft.outerTask = t;// 延时执行delayedExecute(t);return t;}

饰成另一个任务,再拿去执行,这里交给了delayedExecute()方法去执行,这个方法是干嘛的呢?

延时执行。

private void delayedExecute(RunnableScheduledFuture<?> task) {// 如果线程池关闭了,执行拒绝策略if (isShutdown())reject(task);else {// 先把任务扔到队列中去super.getQueue().add(task);    // 再次检查线程池状态if (isShutdown() &&!canRunInCurrentRunState(task.isPeriodic()) &&remove(task))task.cancel(false);else// 保证有足够有线程执行任务ensurePrestart();}}
void ensurePrestart() {// 创建工作线程// 注意,这里没有传入firstTask参数,因为上面先把任务扔到队列中去了    // 另外,没用上maxPoolSize参数,所以最大线程数量在定时线程池中实际是没有用的int wc = workerCountOf(ctl.get());if (wc < corePoolSize)addWorker(null, true);else if (wc == 0)addWorker(null, false);}

实际上,这里只是控制任务能不能被执行,真正执行任务的地方在任务的run()方法中。还记得上面的任务被装饰成了ScheduledFutureTask类的实例吗?所以,我们只要看ScheduledFutureTask的run()方法就可以了。

2.2 ScheduledFutureTask类的run()方法

        /*** 覆盖FutureTask版本,以便在定期重置/重新排队。*/public void run() {// 是否重复执行boolean periodic = isPeriodic();// 线程池状态判断if (!canRunInCurrentRunState(periodic))cancel(false);            // 一次性任务,直接调用父类的run()方法,这个父类实际上是FutureTaskelse if (!periodic)// 重复性任务,先调用父类的runAndReset()方法,这个父类也是FutureTaskScheduledFutureTask.super.run();else if (ScheduledFutureTask.super.runAndReset()) {// 设置下次执行的时间setNextRunTime();// 重复执行reExecutePeriodic(outerTask);}}

可以看到,对于重复性任务,先调用FutureTask的runAndReset()方法,再设置下次执行的时间,最后再调用reExecutePeriodic()方法。

再来看看reExecutePeriodic()方法。

 void reExecutePeriodic(RunnableScheduledFuture<?> task) {// 线程池状态检查if (canRunInCurrentRunState(true)) {// 再次把任务扔到任务队列中super.getQueue().add(task);// 再次检查线程池状态if (!canRunInCurrentRunState(true) && remove(task))task.cancel(false);else                 // 保证工作线程足够ensurePrestart();}}

到这里是不是豁然开朗了,原来定时线程池执行重复任务是在任务执行完毕后,又把任务扔回了任务队列中。重复性的问题解决了,那么,它是怎么控制任务在某个时刻执行的呢?这就轮到我们的延时队列登场了。

3、DelayedWorkQueue内部类

我们知道,线程池执行任务时需要从任务队列中拿任务,而普通的任务队列,如果里面有任务就直接拿出来了,但是延时队列不一样,它里面的任务,如果没有到时间也是拿不出来的,这也是前面分析中一上来就把任务扔进队列且创建Worker没有传入firstTask的原因。延时队列内部是使用“堆”这种数据结构来实现的。在执行定时任务的时候,每个任务的执行时间都不同,所以DelayedWorkQueue的工作就是按照执行时间的升序来排列,执行时间距离当前时间越近的任务在队列的前面(注意:这里的顺序并不是绝对的,堆中的排序只保证了子节点的下次执行时间要比父节点的下次执行时间要大,而叶子节点之间并不一定是顺序的)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/4654.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

安川YASKAWA机器人FS100控制箱维修全攻略

本文将一起探讨安川机器人控制箱维修和YASKAWA机械手FS100控制柜故障&#xff0c;从故障诊断到维修技巧。注意&#xff0c;在安川机械臂控制器FS100维修过程中&#xff0c;遇到复杂的问题&#xff0c;不要犹豫&#xff0c;及时联系子锐机器人&#xff0c;让您的机器人重获新生&…

chrome 安装devtools

chrome 安装devtools 下载安装 链接&#xff1a;https://github.com/vuejs/devtools 选择对应版本&#xff1a; 安装yarn 下载 npm install -g yarn --registryhttps://registry.npmmirror.com进入下载的目录安装依赖 yarn install --registryhttps://registry.npmmirror.…

一篇了解reactor框架特性

一篇了解reactor框架特性 本文档的一些典型的名词如下&#xff1a; Publisher&#xff08;发布者&#xff09;、Subscriber&#xff08;订阅者&#xff09;、Subscription&#xff08;订阅 n.&#xff09;、subscribe&#xff08;订阅 v.&#xff09;。event/signal&#xff0…

抖音 通用交易系统 下单 密钥生成

已PHP为例 前提提条件 必须在 linux 系统中 生成 准备工作 在小程序中 生成应用公匙 把生成的公匙 复制 在linux 系统中 创建文件 private_key.pem 并将公匙粘贴 接下来打开命令 执行命令即可 openssl genrsa -out private_key.pem 2048 rsa -in private_key.pem -pubo…

分治策略 --- 快排归并

目录 分治-快排 一、颜色分类 二、排序数组 三、数组中的第K个最大元素 四、库存管理 分治-归并 一、排序数组 二、交易逆序对的总数 三、计算右侧小于当前元素的个数 四、翻转对 分治是一种思想&#xff0c;也就是将大问题分解成小问题&#xff0c;一直分到小问题可…

【Camera KMD ISP SubSystem笔记】CAM SYNC与DRQ②

DRQ的作用&#xff1a; DRQ负责调度管理pipeline里的node处理逻辑(通过node之间的dependency依赖机制) 利用多线程并行处理Pipeline中并行的node&#xff0c;加快处理速度 DRQ运转流程&#xff1a; DRQ先告诉node fill dependency&#xff0c; 此时seq id 为0…

如何优雅的实现 iframe 多层级嵌套通讯

前言 在前端开发项目中&#xff0c;不可避免的总会和 iframe 进行打交道&#xff0c;我们通常会使用 postMessage 实现消息通讯。 如果存在下面情况&#xff1a; iframe 父子通讯iframe 同层级通讯iframe 嵌套层级通讯 当面对这种复杂的情况的时候&#xff0c;通讯不可避免…

Unity 物体触碰事件监听

声明委托 public delegate void MyDelegate(Collider trigger); C# 委托&#xff08;Delegate&#xff09; | 菜鸟教程 (runoob.com)https://www.runoob.com/csharp/csharp-delegate.html 定义委托 public MyDelegate onTriggerEnter; public MyDelegateonTriggerStay; pub…

用来传输文件的协议-FTP

一.FTP协议--文件传输协议 1.了解FTP协议 &#xff08;1&#xff09;FTP服务是用来传输文件的协议 FTP&#xff08;File Transfer Protocol&#xff0c;文件传输协议&#xff09;是TCP/IP协议组中的协议之一&#xff0c;用于互联网上的控制文件的双向传输。是传输文件到Linu…

《Fundamentals of Power Electronics》——全桥型隔离降压转换器

以下是关于全桥型隔离降压转换器的相关知识点&#xff1a; 全桥变压器隔离型降压转换器如下图所示。 上图展示了一个具有二次侧绕组中心抽头的版本&#xff0c;该电路常用于产生低输出电压。二次侧绕组的上下两个绕组可以看作是两个单独的绕组&#xff0c;因此可以看成是具有变…

Internal server error: [less] Unrecognised input

我之前查了资料&#xff0c;网上有的人说是 less 的配置不正确&#xff08;这种问题引起的可以查找其他博客看&#xff09;&#xff0c;但是后面经过我慢慢的查找&#xff0c;还有一种可能&#xff0c;就是 less 的写法不对&#xff0c;下面我来解释一下我的错误和处理过程 在…

kaggle无法注册怎么办

在浏览kaggle网站&#xff0c;或者是参加kaggle竞赛时&#xff0c;常常会遇到需要登陆kaggle账号的情况。而在注册时&#xff0c;却发现无论如何也无法弹出人机识别的验证码&#xff0c;导致无法注册成功。本文会手把手的讲解一种注册kaggle的方法&#xff08;edge浏览器&#…

安装依赖报错前端安装某个依赖安装不上可能是node版本过高 升级或者降低node版本方式

安装依赖报错安装某个依赖安装不上可能是node版本过高 升级或者降低node版本方式 安装某个依赖安装不上 或者node版本过高 升级或者降低node版本 收藏关注一下吧 开发中难免总会需要切换node版本 需要的时候在找麻烦 主页 中还有更多干货分享

分享开放原子AtomGit开源协作平台评测报告

AtomGit平台的总体介绍 开放原子开源基金会是致力于推动全球开源事业发展的非营利机构&#xff0c;于 2020 年 6 月在北京成立&#xff0c;由阿里巴巴、百度、华为、浪潮、360、腾讯、招商银行等多家龙头科技企业联合发起。目前有三个主要机构设置&#xff0c;技术监督委员会&…

You need know something from Xcode 9

xcode 9 一些快捷的功能使用介绍 首先是弹框 目前发现弹框中的提取方法等功能存在一些问题&#xff0c;期待后续的版本能解决这些问题&#xff0c;弹框里面主要包含跳转变量或者方法的跳转、快捷帮助、折叠方法、重命名方法名称、提取方法等功能 笔者觉得rename功能比较好用&…

【新手入门】Git的使用方法,上传自己的项目到GitHub上

Git新手教程 一、Git下载安装二、初始化设置1.网端设置2.用户设置 三、开始上传自己项目1.创建新文件夹&#xff0c;克隆项目地址2.上传文件3.成功运行并上传的界面 报错1.fatal: unable to access https://github.com/ssrzero123/STF-YOLO.git/: error setting certificate fi…

NDK 编译(二)—— NDK 编译与集成 FFmpeg

NDK 编译系列文章共三篇&#xff0c;目录如下&#xff1a; NDK 编译&#xff08;一&#xff09;—— Linux 知识汇总 NDK 编译&#xff08;二&#xff09;—— NDK 编译与集成 FFmpeg NDK 编译&#xff08;三&#xff09;—— CMake 原生构建工具 在使用 NDK 进行音视频开发时&…

icloud里面的通讯录怎么全部导出,通讯录格式如何转换,简单!

随着科技的发展&#xff0c;我们的日常生活越来越离不开手机和各种应用程序。通讯录作为手机中最重要的功能之一&#xff0c;记录着我们的亲朋好友、同事和业务伙伴的联系方式。因此&#xff0c;定期备份通讯录变得尤为重要。iCloud作为苹果公司提供的一项云服务&#xff0c;可…

【触摸案例-控件不能响应的情况 Objective-C语言】

一、接下来,我们来说这个“控件不能响应的情况”, 1.素材里边,有一个“不接受用户交互的情况”,这么一个代码,把它打开, 把这个项目啊,复制过来,改一个名字,叫做“04-控件不能响应的情况”, 打开之后,command + R,运行一下, 在storyboard上,你也可以看得出来,我…

java-stream流案例

需求 代码 Vote类 // 1. 定义一个投票类 public class Vote {private String name;private ArrayList<String> voteList;public Vote(String name, ArrayList<String> voteList) {this.name name;this.voteList voteList;}public String getName() {return nam…