调度线程池 ScheduledThreadPoolExecutor 的正确使用姿势

news2024/11/19 4:38:34

前言

项目中经常会遇到一些非分布式的调度任务,需要在未来的某个时刻周期性执行。实现这样的功能,我们有多种方式可以选择:

  1. Timer类, jdk1.3 引入,不推荐

它所有任务都是串行执行的,同一时间只能有一个任务在执行,而且前一个任务的延迟或异常都将会影响到之后的任务。

  1. Spring 的@Scheduled注解,不是很推荐

这种方式底层虽然是用线程池实现,但是有个最大的问题,所有的任务都使用的同一个线程池,可能会导致长周期的任务运行影响短周期任务运行,造成线程池"饥饿",更加推荐的做法是同种类型的任务使用同一个线程池。

  1. 自定义ScheduledThreadPoolExecutor实现调度任务

这也是本文重点讲解的方式,通过自定义ScheduledThreadPoolExecutor调度线程池,提交调度任务才是最优解。

创建方式

创建ScheduledThreadPoolExecutor方式一共有两种,第一种是通过自定义参数,第二种通过Executors工厂方法创建。 根据阿里巴巴代码规范中的建议,更加推荐我们使用第一种方式创建。

  1. 自定义参数创建

ScheduledThreadPoolExecutor(int corePoolSize,                                       ThreadFactory threadFactory,                                       RejectedExecutionHandler handler)
  • corePoolSize:核心工作的线程数量

  • threadFactory:线程工厂,用来创建线程

  • handler: 拒绝策略,饱和策略

  1. Executors工厂方法创建

  • static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)

根据核心线程数创建调度线程池。

  • static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory)

根据核心线程数和线程工厂创建调度线程池。

核心 API

  1. schedule(Runnable command, long delay, TimeUnit unit)

创建并执行在给定延迟后启用的一次性操作

  • command: 执行的任务

  • delay:延迟的时间

  • unit: 单位

  1. scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)

定时执行周期任务,任务执行完成后,延迟 delay 时间执行

  • command: 执行的任务

  • initialDelay: 初始延迟的时间

  • delay: 上次执行结束,延迟多久执行

  • unit:单位

@Testpublic void testScheduleWithFixedDelay() throws InterruptedException {    // 创建调度任务线程池    ScheduledExecutorService scheduledExecutorService = new ScheduledThreadPoolExecutor(1);    // 按照上次执行完成后固定延迟时间调度    scheduledExecutorService.scheduleWithFixedDelay(() -> {        try {            log.info("scheduleWithFixedDelay ...");            Thread.sleep(1000);        } catch (InterruptedException e) {            e.printStackTrace();        }    }, 1, 2, TimeUnit.SECONDS);
    Thread.sleep(10000);}

  1. scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)

按照固定的评率定时执行周期任务,不受任务运行时间影响。

  • command: 执行的任务

  • initialDelay: 初始延迟的时间

  • period: 周期

  • unit:单位

 @Testpublic void testScheduleAtFixedRate() throws InterruptedException {    // 创建调度任务线程池    ScheduledExecutorService scheduledExecutorService = new ScheduledThreadPoolExecutor(1);    // 按照固定2秒时间执行    scheduledExecutorService.scheduleAtFixedRate(() -> {        try {            log.info("scheduleWithFixedDelay ...");            Thread.sleep(1000);        } catch (InterruptedException e) {            e.printStackTrace();        }    }, 1, 2, TimeUnit.SECONDS);
    Thread.sleep(10000);}

tips: 以上 API 全部返回ScheduledExecutorService类,调用调用getDelay()可以获取任务下次的执行时间点,非常好用的。

@Testpublic void testResp() throws InterruptedException {    // 创建调度任务线程池    ScheduledExecutorService scheduledExecutorService = new ScheduledThreadPoolExecutor(1);    // 按照上次执行完成后固定延迟5秒时间调度    ScheduledFuture<?> scheduledFuture = scheduledExecutorService.scheduleWithFixedDelay(() -> {        log.info("exec schedule ...");    }, 1, 5, TimeUnit.SECONDS);
    while (true) {        // 获取剩余时间        long delay = scheduledFuture.getDelay(TimeUnit.SECONDS);        log.info("下次执行剩余时间{}秒", delay);       Thread.sleep(1000);    }}

综合例子

下面我们演示个例子,通过ScheduledThreadPoolExecutor实现每周四 18:00:00 定时执行任务。

// 通过ScheduledThreadPoolExecutor实现每周四 18:00:00 定时执行任务@Testpublic void test() {    //  获取当前时间    LocalDateTime now = LocalDateTime.now();    System.out.println(now);    // 获取周四时间    LocalDateTime time = now.withHour(18).withMinute(0).withSecond(0).withNano(0).with(DayOfWeek.THURSDAY);    // 如果 当前时间 > 本周周四,必须找到下周周四    if(now.compareTo(time) > 0) {        time = time.plusWeeks(1);    }    System.out.println(time);    // initailDelay 代表当前时间和周四的时间差    // period 一周的间隔时间    long initailDelay = Duration.between(now, time).toMillis();    long period = 1000 * 60 * 60 * 24 * 7;    ScheduledExecutorService pool = Executors.newScheduledThreadPool(1);    pool.scheduleAtFixedRate(() -> {        System.out.println("running...");    }, initailDelay, period, TimeUnit.MILLISECONDS);}

使用注意事项

使用 ScheduledThreadPoolExecutor 时一定要注意异常处理, 如果使用不当,会导致定时任务不再执行,记住要 try catch 捕获异常,具体参考这篇文章:ScheduledThreadPoolExecutor踩过最痛的坑。

总结

本文主要讲解了ScheduledThreadPoolExecutor这个线程池类的使用,可以用来实现我们的调度任务,那么它是怎么实现的,我们也可以思考下。

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

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

相关文章

【C语言】移位操作符 位操作符 - 对二进制位进行精准操作【+面试题目】_[初阶篇]

快速导航 【前言】 1.移位操作符 1.1左移操作符(<<) 1.2右移操作符(>>) 2.位操作符 2.1 & 按位与 2.2 | (按位或) 2.3 ^ (按位异或) 3.面试题目 3.1 交换两个变量&#xff08;不创建临时变量&#xff09; 3.2统计二进制中1的个数 3.2.1 方法一&#xff1a;…

复合事件归因分析

1 复合事件 1.1 概述 1.2 类型 1.2.1 先决条件事件&#xff08;preconditioned events&#xff09; 1.2.2 多变量事件&#xff08;multivariate CEs&#xff09; eg.高温干旱 1.2.3 时间复合事件&#xff08;temporally CEs&#xff09; eg.旱涝急转 1.2.4 空间复合事件…

电子电路设计基本概念100问(二)【学习目标:原理图、PCB、阻抗设计、电子设计基本原则、基本原器件等】

笔者电子信息专业硕士毕业&#xff0c;获得过多次电子设计大赛、大学生智能车、数学建模国奖&#xff0c;现就职于南京某半导体芯片公司&#xff0c;从事硬件研发&#xff0c;电路设计研究。对于学电子的小伙伴&#xff0c;深知入门的不易&#xff0c;特开次博客交流分享经验&a…

【每天学习一点新知识】网络安全--拒绝服务攻击

目录 1、SYN泛洪攻击 SYN泛洪攻击原理 攻击过程 防御机制 2、Smurf攻击 Smurf攻击原理 间接攻击 放大攻击 防御机制 3、DDoS DDoS原理 直接DDoS攻击 间接DDoS攻击 防御机制 1、SYN泛洪攻击 SYN泛洪攻击原理 终端访问Web服务器之前需要和服务器之间建立TCP连接。W…

万字长文解析Scaled YOLOv4模型(YOLO变体模型)

一&#xff0c;Scaled YOLOv4 摘要1&#xff0c;介绍2&#xff0c;相关工作 2.1&#xff0c;模型缩放 3&#xff0c;模型缩放原则 3.1&#xff0c;模型缩放的常规原则3.2&#xff0c;为低端设备缩放的tiny模型3.3&#xff0c;为高端设备缩放的Large模型 4&#xff0c;Scaled-YO…

大学毕业后,我就送了2个月外卖,哭了一整晚

先简单介绍一下自己&#xff0c;我来自湛江&#xff0c;大学学的的物流管理专业&#xff0c;现在就职于一家互联网公司&#xff0c;从事软件测试工作。 我来自湛江的一个偏远农村&#xff0c;家里兄弟姐妹多&#xff0c;父母无力负担我的学费&#xff0c;很多时候学费都是靠姐…

红黑树 - c++

文章目录&#xff1a;红黑树的介绍红黑树节点定义红黑树的插入操作红黑树的删除红黑树的验证红黑树 vs AVL树红黑树的介绍 红黑树(Red-Black-Tree)&#xff0c;通常写为 R-B Tree。它是一种特殊的二叉搜索树。红黑树的每个节点上都有一个存储位来标识节点的颜色&#xff0c;可…

积木报表—JimuReport v1.5.4版本发布,免费的可视化Web报表工具

项目介绍 一款免费的低代码可视化报表&#xff0c;像搭建积木一样在线拖拽设计&#xff01;低代码开发必备&#xff0c;功能涵盖&#xff0c;数据报表、打印设计、图表报表、大屏设计等&#xff01; 秉承“简单、易用、专业”的产品理念&#xff0c;极大的降低报表开发难度、缩…

【css伪类选择器及透明度——附项目图片及代码】

不知不觉&#xff0c;又鸽了好长时间了&#xff0c;非常抱歉&#xff0c;没办法&#xff0c;毕竟开学了&#xff0c;今天课少&#xff0c;抽出了两个小时写了一篇css的&#xff0c;每天不是被催更&#xff0c;就是在催更的路上。放心&#xff0c;小陈陈有时间一定会给大家分享好…

SVM 支持向量机

SVM 支持向量机SVM 原理最优化问题线性不可分sklearn 调用 SVM核函数SVM 原理 前置知识&#xff1a;用迭代策略来划分样本&#xff0c;请猛击《神经元的计算》。 SVM 也是用一条迭代的直线来划分不同数据之间的边界&#xff1a; .- 是一条直线&#xff08;线性函数&#xff09…

数据结构c语言版第二版(严蔚敏)第五章笔记

目录 树和二叉树的定义 树的定义 树的基本术语 二叉树的定义 二叉树的性质和存储结构 二叉树的性质 二叉树的存储结构 顺序存储结构 链式存储结构 遍历二叉树和线索二叉树 遍历二叉树 先序遍历 中序遍历 后序遍历 前序遍历的递归算法 中序遍历的递归算法 后序…

SARScape中用sentinel-1数据做SBAS-InSAR完整流程(2/2)

书接上回&#xff1a;SARScape中用sentinel-1数据做SBAS-InSAR完整流程&#xff08;1/2&#xff09; SARScape中用sentinel-1数据做SBAS-InSAR完整流程&#xff08;2/2&#xff09;7 反演第一步Inversion&#xff1a;First Step7.1 导入设置7.2 optional file7.3 parameters参数…

齐博x1用户登录接口

用户的登录主要涉及到小程序登录、APP的帐号密码登录、APP的微信开发平台帐号登录。 相应的地址是&#xff1a;http://qb.net/index.php/index/wxapp.login/index.html 涉及到的方法如下 上面的地址&#xff0c;默认是小程序的登录与注册。 http://qb.net/index.php/index/wxa…

matlab/simulink电力电子仿真傅里叶变换模块(fourier)测幅值相角的设置与使用

matlab/simulink电力电子仿真傅里叶变换模块&#xff08;fourier&#xff09;测幅值相角的设置与使用 今天要说的是一个可以测量信号的幅值和相角的模块&#xff0c;fourier&#xff0c;长下面这样&#xff1a; 有时候我们需要求某个信号的幅值或者相位&#xff0c;或求两个…

用文字描述给黑白照上色,这个免费网站火了!网友:比其他同类都好用

金磊 Alex 发自 凹非寺量子位 | 公众号 QbitAI这是清朝末代皇后婉容广为流传的一张老照片&#xff1a;如果让照片变成彩色的&#xff0c;会是什么样子&#xff1f;竟然没有什么违和感&#xff0c;百年前的老照片似乎在此刻变得鲜活了起来。而这张图上色的背后&#xff0c;并没有…

BUUCTF NewStarCTF 公开赛赛道Week5 Writeup

文章目录WEBGive me your photo PLZBabySSTI_ThreeUnsafe ApacheSo Baby RCE AgainFinal roundMISC最后的流量分析奇怪的PDF 2奇怪的文本Yesec no drumsticks 5qsdzs girlfriend 5WEB Give me your photo PLZ 可上传.htaccess AddType application/x-httpd-php .jpg然后上传…

干货!手把手教你穿透内网

干货&#xff01;手把手教你穿透内网干货&#xff01;手把手教你穿透内网cpolar内网穿透使用场景如何使用cpolar内网穿透&#xff1f; ↓↓1. 注册cpolar账号2. 安装cpolar内网穿透2.1 Windows系统2.2 Linux系统2.2.1 安装2.2.2 向系统添加服务2.2.3 启动服务2.2.4 查看服务状态…

生成二维码或条形码JavaScript脚本库

二维码或条形码在日常生活中现在应用已经非常普遍了&#xff0c;文章分享生成条形码和二维码的JavaScript库。 条形码 条形码是日常生活中比较常见的&#xff0c;主要用于商品。通俗的理解就是一串字符串的集合&#xff08;含字母、数字及其它ASCII字符的集合应用&#xff09…

【机器学习基础】 线性回归

线性回归1、线性回归定义2、线性回归题目示例3、推导公式4、误差5、似然函数6、线性回归评价指标7、梯度下降1、线性回归定义 经典统计学习技术中的线性回归和softmax回归可以视为 线性神经⽹络。给定训练数据特征 X 和对应的已知标签 y &#xff0c;线性回归的⽬标是找到⼀组权…

Seata安装启动

一、下载 https://github.com/seata/seata/releases/download/v1.4.2/seata-server-1.4.2.zip 二、启动 在安装路径下cmd seata-server.bat -h 127.0.0.1 -m file 三、作用 Seata是分布事务解决方案&#xff0c;seata保证微服务远程调用业务的原子性 Seata将为用户提供了 …