深入理解和使用定时线程池ScheduledThreadPoolExecutor

文章目录

  • 前言
  • 认识定时线程池
    • 什么是定时线程池?
    • 定时线程池基本API使用
    • 定时线程池的应用场景
      • 1、定时任务调度
      • 2、缓存过期清理
      • 3、心跳检测
      • 4、延迟任务执行
  • 定时线程池scheduleAtFixedRate与scheduleWithFixedDelay区别
    • scheduleAtFixedRate案例demo(period,任务之间间隔)
    • scheduleWithFixedDelay案例demo(delay,上一个任务结束后间隔时间)
  • ScheduledThreadPoolExecutor源码
    • 如何实现队列任务的捞取(即任务的调度和执行)?
      • 认识DelayedWorkQueue
      • 理解DelayedWorkQueue#take
      • 捞取和执行流程
  • 参考文章
  • 资料获取

前言

博主介绍:✌目前全网粉丝3W+,csdn博客专家、Java领域优质创作者,博客之星、阿里云平台优质作者、专注于Java后端技术领域。

涵盖技术内容:Java后端、大数据、算法、分布式微服务、中间件、前端、运维等。

博主所有博客文件目录索引:博客目录索引(持续更新)

CSDN搜索:长路

视频平台:b站-Coder长路

本章节配套源码:

  • gitee:https://gitee.com/changluJava/demo-exer/tree/master/JUC/src/main/java/demo12

认识定时线程池

什么是定时线程池?

定时线程池是一种专门用于执行定时任务的线程池,它结合了线程池的优势和定时任务的功能,能够高效地管理和调度任务。

定时线程池是一种特殊的线程池,它不仅可以执行普通任务,还可以安排任务在未来某个时间点执行,或者以固定的速率重复执行。

在Java中,ScheduledThreadPoolExecutor是实现定时线程池的核心类。


定时线程池基本API使用

1、创建定时线程池

ScheduledExecutorService executor = Executors.newScheduledThreadPool(5); // 创建一个包含5个线程的定时任务线程池

2、提交一次性任务

executor.schedule(new Task("one-time"), 1, TimeUnit.SECONDS); // 在1秒后执行任务

3、提交固定速率任务

executor.scheduleAtFixedRate(new Task("fixed-rate"), 2, 3, TimeUnit.SECONDS); // 在2秒后开始执行任务,每隔3秒重复执行

4、提交固定延迟任务

executor.scheduleWithFixedDelay(new Task("fixed-delay"), 2, 3, TimeUnit.SECONDS); // 在2秒后开始执行任务,每次执行完毕后等待3秒再执行下一次

5、关闭线程池

executor.shutdown(); // 优雅关闭线程池,等待所有任务完成
executor.shutdownNow(); // 强制关闭线程池,停止所有任务

定时线程池的应用场景

1、定时任务调度

场景描述:需要定期执行某些任务,比如每天凌晨清理日志、每小时统计系统数据等。

实现方式:使用 scheduleAtFixedRatescheduleWithFixedDelay 方法,设置任务的执行间隔。

示例

ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
executor.scheduleAtFixedRate(() -> {System.out.println("执行每日数据备份任务: " + new Date());
}, 0, 24, TimeUnit.HOURS); // 每隔24小时执行一次

2、缓存过期清理

场景描述:在缓存系统中,需要定期清理过期的缓存数据。

实现方式:使用定时线程池定期扫描缓存,清理过期的数据。

示例

ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
executor.scheduleAtFixedRate(() -> {cache.cleanExpiredEntries(); // 清理过期缓存System.out.println("缓存清理完成: " + new Date());
}, 0, 1, TimeUnit.HOURS); // 每隔1小时清理一次

3、心跳检测

场景描述:在分布式系统中,需要定期向其他服务发送心跳包,检测服务是否存活。

实现方式:使用定时线程池定期发送心跳请求。

示例

ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
executor.scheduleAtFixedRate(() -> {boolean isAlive = heartBeatCheck(); // 发送心跳检测if (!isAlive) {System.out.println("服务不可用,触发告警!");}
}, 0, 10, TimeUnit.SECONDS); // 每隔10秒检测一次

4、延迟任务执行

场景描述:某些任务需要延迟一段时间后执行,比如订单超时未支付自动取消。

实现方式:使用 schedule 方法,设置任务的延迟时间。

示例

ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
executor.schedule(() -> {orderService.cancelOrder(orderId); // 取消订单System.out.println("订单已取消: " + orderId);
}, 30, TimeUnit.MINUTES); // 延迟30分钟执行

定时线程池scheduleAtFixedRate与scheduleWithFixedDelay区别

image-20250205224359033

scheduleAtFixedRate案例demo(period,任务之间间隔)

说明:scheduleAtFixedRate 方法:第三个参数是period,表示每间隔period时间执行一次任务(如果period为2s,但是前一个任务为3s,此时会在前一个任务执行完后再执行)。

public class ScheduledThreadPoolExecutorDemo {public static void main(String[] args) {test01();}// scheduleAtFixedRate 方法:第三个参数是period,表示每间隔period时间执行一次任务(如果period为2s,但是前一个任务为3s,此时会在前一个任务执行完后再执行)public static void test01() {ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);// 第0s开始执行,每间隔2s执行一次任务executor.scheduleAtFixedRate(() -> {LocalDateTime startTime = LocalDateTime.now();System.out.println("Task started at: " + startTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) + ", thread: " + Thread.currentThread().getName());try {Thread.sleep(3000); // 模拟任务耗时3秒} catch (InterruptedException e) {e.printStackTrace();}LocalDateTime endTime = LocalDateTime.now();System.out.println("Task finished at: " + endTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));}, 0, 2, TimeUnit.SECONDS);}}

效果如下:

image-20250205224710125

scheduleWithFixedDelay案例demo(delay,上一个任务结束后间隔时间)

说明:scheduleWithFixedDelay:第三个参数为delay,指的是上一个任务执行完之后间隔delay来执行任务

public class ScheduledThreadPoolExecutorDemo {public static void main(String[] args) {test02();}// scheduleWithFixedDelay:第三个参数为delay,指的是上一个任务执行完之后间隔delay来执行任务public static void test02() {ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);executor.scheduleWithFixedDelay(() -> {LocalDateTime startTime = LocalDateTime.now();System.out.println("Task started at: " + startTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) + ", thread: " + Thread.currentThread().getName());try {Thread.sleep(3000); // 模拟任务耗时3秒} catch (InterruptedException e) {e.printStackTrace();}LocalDateTime endTime = LocalDateTime.now();System.out.println("Task finished at: " + endTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));}, 0, 2, TimeUnit.SECONDS);}
}

效果如下:

image-20250205225001345

ScheduledThreadPoolExecutor源码

如何实现队列任务的捞取(即任务的调度和执行)?

认识DelayedWorkQueue

DelayedWorkQueue是一个基于优先队列的无界阻塞队列,用于存储ScheduledFutureTask对象。它按照任务的触发时间排序,确保最早到期的任务优先出队。

关键方法

  • poll:从队列中取出最早到期的任务。
  • offer:将任务添加到队列中。
  • take:阻塞等待,直到队列中有任务到期。

任务的封装(ScheduledFutureTask)ScheduledFutureTaskScheduledThreadPoolExecutor中用于封装任务的类。它继承自FutureTask,并添加了与调度相关的逻辑。

关键字段

  • sequenceNumber:任务的序列号,用于解决触发时间相同的情况。
  • period:任务的周期(对于scheduleAtFixedRate)或延迟(对于scheduleWithFixedDelay)。
  • time:任务的下次触发时间。

关键方法

  • run:执行任务逻辑。
  • setNextRunTime:设置任务的下次触发时间。

理解DelayedWorkQueue#take

核心任务调度:ScheduledThreadPoolExecutor的工作线程会不断地从DelayedWorkQueue中捞取任务并执行。

DelayedWorkQueuetake方法

public ScheduledFutureTask<?> take() throws InterruptedException {final ReentrantLock lock = this.lock;lock.lockInterruptibly();try {for (;;) {// 获取当前时间long currentTime = now();// 获取队列头部的任务ScheduledFutureTask<?> first = queue.peek();if (first == null) {// 如果队列为空,等待available.await();} else {// 如果任务已经到期if (first.isPeriodic() && first.getPeriod() < 0) {// 周期性任务,重新计算下次触发时间long period = first.getPeriod();long nextTime = first.getNextExecutionTime();first.setNextExecutionTime(nextTime + period);first.setPeriod(period);}if (first.getDelay(NANOSECONDS) <= 0) {// 任务到期,移除并返回return queue.poll();}// 如果任务未到期,等待long delay = first.getDelay(NANOSECONDS);if (leader == null) {leader = Thread.currentThread();available.awaitNanos(delay);leader = null;} else {available.awaitNanos(delay);}}}} finally {lock.unlock();}
}

捞取和执行流程

捞取和执行流程如下:

  1. 任务添加到队列
    • 当调用scheduleAtFixedRatescheduleWithFixedDelay时,任务被封装为ScheduledFutureTask对象,并添加到DelayedWorkQueue中。
    • DelayedWorkQueue会按照任务的触发时间排序。
  2. 工作线程捞取任务
    • 工作线程通过调用DelayedWorkQueuetake方法来获取最早到期的任务。
    • 如果任务尚未到期,工作线程会阻塞等待。
  3. 任务执行
    • 工作线程获取任务后,调用任务的run方法来执行任务。
    • 如果任务是周期性任务(如scheduleAtFixedRate),任务执行完成后会重新计算下次触发时间,并再次添加到队列中。

参考文章

[1]. Java并发包线程池之ScheduledThreadPoolExecutor:https://www.cnblogs.com/txmfz/p/11222873.html


资料获取

大家点赞、收藏、关注、评论啦~

精彩专栏推荐订阅:在下方专栏👇🏻

  • 长路-文章目录汇总(算法、后端Java、前端、运维技术导航):博主所有博客导航索引汇总
  • 开源项目Studio-Vue—校园工作室管理系统(含前后台,SpringBoot+Vue):博主个人独立项目,包含详细部署上线视频,已开源
  • 学习与生活-专栏:可以了解博主的学习历程
  • 算法专栏:算法收录

更多博客与资料可查看👇🏻获取联系方式👇🏻,🍅文末获取开发资源及更多资源博客获取🍅


整理者:长路 时间:2025.2.5

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

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

相关文章

【React】合成事件语法

React 合成事件是 React 为了处理浏览器之间的事件差异而提供的一种跨浏览器的事件系统。它封装了原生的 DOM 事件&#xff0c;提供了一致的事件处理机制。 合成事件与原生事件的区别&#xff1a; 合成事件是 React 自己实现的&#xff0c;封装了原生事件。合成事件依然可以通…

中小企业的采购流程,采购管理是如何进行的?

经营中小企业的&#xff0c;都明白高效采购管理的重要性。我见过不少中小企业&#xff0c;采购环节混乱无序&#xff0c;花费大量成本&#xff0c;却难以保障物资的优质供应。然而到底该如何梳理采购流程&#xff0c;怎样开展采购管理工作呢&#xff1f;这让众多中小企业主愁眉…

在线教程丨YOLO系列10年更新11个版本,最新模型在目标检测多项任务中达SOTA

YOLO (You Only Look Once) 是计算机视觉领域中最具影响力的实时目标检测算法之一&#xff0c;以其高精度与高效性深受业界青睐&#xff0c;广泛应用于自动驾驶、安防监控、医疗影像等领域。 该模型最早于 2015 年由华盛顿大学研究生 Joseph Redmon 发布&#xff0c;开创了将目…

IOPS与吞吐量、读写块大小及延迟之间的关系

IOPS&#xff08;每秒输入/输出操作次数&#xff09;、吞吐量、读写块大小及延迟是衡量存储系统性能的四个关键指标&#xff0c;它们之间存在密切的关系。以下从多个方面详细说明这些指标之间的关系&#xff1a; 1. IOPS与吞吐量的关系 公式关系&#xff1a;吞吐量&#xff0…

DeepSeek 部署过程中的问题

文章目录 DeepSeek 部署过程中的问题一、部署扩展&#xff1a;docker 部署 DS1.1 部署1.2 可视化 二、问题三、GPU 设置3.1 ollama GPU 的支持情况3.2 更新 GPU 驱动3.3 安装 cuda3.4 下载 cuDNN3.5 配置环境变量 四、测试 DeepSeek 部署过程中的问题 Windows 中 利用 ollama 来…

DeepSeek RAGFlow构建本地知识库系统

学习目标 DeepSeek RAGFlow 构建本地知识库系统 学习内容 下载安装Docker 1.1 Docker 是什么 1.2 下载Docker 1.3 安装Docker配置DockerRAGFlow 配置 3.1 下载RAGFlow 3.2 RAGFlow配置 3.3 启动RAGFlow Docker新建知识库 4.1 查看本机IP 4.2 OLLAMA_HOST 变量配置 4.3 添加模…

11 享元(Flyweight)模式

享元模式 1.1 分类 &#xff08;对象&#xff09;结构型 1.2 提出问题 做一个车管所系统&#xff0c;将会产生大量的车辆实体&#xff0c;如果每一个实例都保存自己的所有信息&#xff0c;将会需要大量内存&#xff0c;甚至导致程序崩溃。 1.3 解决方案 运用共享技术有效…

arcgis for js范围内天地图高亮,其余底图灰暗

在GIS地图开发中&#xff0c;有时我们需要突出显示某个特定区域&#xff0c;而将其他区域灰暗处理&#xff0c;以达到视觉上的对比效果。本文将介绍如何使用ArcGIS for JavaScript实现这一功能&#xff0c;具体效果为&#xff1a;在指定范围内&#xff0c;天地图高亮显示&#…

Spring AI + Ollama 实现 DeepSeek-R1 API 服务和调用

随着大语言模型的快速发展&#xff0c;越来越多的开发者开始探索如何将这些强大的推理模型本地化运行。DeepSeek-R1&#xff0c;作为一款性能卓越的开源AI模型&#xff0c;以其低成本和出色的推理能力在技术圈内引起了广泛关注。本文将详细介绍如何使用Ollama部署DeepSeek-R1&a…

Ubuntu 20.04配置网络

1&#xff0c;检查自己网络是否配通。 网络配置成功显示的网络图标 不成功的网络图标 如果看不见网络图标&#xff0c;可以使用ping命令。连接一下百度网。 ping www.baidu.com ping失败的样子 ping成功的样子 2&#xff0c;接下来进入正题&#xff0c;我们开始配置网络。 这…

ElasticSearch入门

目录 1._cat 2.索引一个 document 3.查询document 4.更新document 5.删除document 或 index 6.批量_bulk API 1._cat Get/_cat/nodes 查看所有节点 Get/_cat/indices 查看所有索引&#xff08;indices &#xff1a;index的复数) Get/_cat/master 查看…

java练习(8)

ps:题目来自力扣 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。 假设 nums 中不等于 val 的元素数量为 k&#xff0c;要通过此题&#xff0c;您需要执行以下操作…

Java常用类

文章目录 包装类(Wrapper)包装类的继承体系装箱和拆箱包装类与String类型的相互转换 String类创建 String 对象的两种方式String 类的常见方法案例演示 StringBuffer类类的继承体系String VS StringBufferStringBuffer构造器String 和 StringBuffer 相互转换StringBuffer 类常见…

算法设计与分析三级项目--管道铺设系统

摘 要 该项目使用c算法逻辑&#xff0c;开发环境为VS2022&#xff0c;旨在通过Prim算法优化建筑物间的连接路径&#xff0c;以支持管线铺设规划。可以读取文本文件中的建筑物名称和距离的信息&#xff0c;并计算出建筑物之间的最短连接路径和总路径长度&#xff0c;同时以利用…

【C语言系列】深入理解指针(5)

深入理解指针&#xff08;5&#xff09; 一、sizeof和strlen的对比1.1sizeof1.2strlen1.3sizeof和strlen的对比 二、数组和指针笔试题解析2.1 一维数组2.2 字符数组2.2.1代码1&#xff1a;2.2.2代码2&#xff1a;2.2.3代码3&#xff1a;2.2.4代码4&#xff1a;2.2.5代码5&#…

设计模式——策略模式

设计模式——策略模式 简单介绍一个例子 策略模式是设计模式里面比较简单的设计模式&#xff0c;其特点简单又实用&#xff0c;并且可以让你的代码看起来高大上&#xff0c;维护代码时还方便扩张 多重条件语句不易维护&#xff0c;而使用策略模式可以避免使用多重条件语句&…

【玩转 Postman 接口测试与开发2_018】第14章:利用 Postman 初探 API 安全测试

《API Testing and Development with Postman》最新第二版封面 文章目录 第十四章 API 安全测试1 OWASP API 安全清单1.1 相关背景1.2 OWASP API 安全清单1.3 认证与授权1.4 破防的对象级授权&#xff08;Broken object-level authorization&#xff09;1.5 破防的属性级授权&a…

MySQL的 MVCC详解

MVCC是多版本并发控制&#xff0c;允许多个事务同时读取和写入数据库&#xff0c;而无需互相等待&#xff0c;从而提高数据库的并发性能。 在 MVCC 中&#xff0c;数据库为每个事务创建一个数据快照。每当数据被修改时&#xff0c;MySQL不会立即覆盖原有数据&#xff0c;而是生…

【Uniapp-Vue3】z-paging插件组件实现触底和下拉加载数据

一、下载z-paing插件 注意下载下载量最多的这个 进入Hbuilder以后点击“确定” 插件的官方文档地址&#xff1a; https://z-paging.zxlee.cn 二、z-paging插件的使用 在文档中向下滑动&#xff0c;会有使用方法。 使用z-paging标签将所有的内容包起来 配置标签中的属性 在s…

UG NX二次开发(Python)-API函数介绍与应用实例(三)-UFLayer类操作

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 1 前言2、UFLayer类说明3、获取当前工作图层4、移动对象到特定的图层1 前言 采用Python语言进行UG NX二次开发的帮助材料很少,采用录制的方法是一种比较容易实现的方式,但是使用UFun函数更容易上…