Spring Boot中使用ThreadPoolTaskScheduler实现轻量级多线程定时任务
引言
在Java开发中,Spring Boot提供了多种方式来执行定时任务,如@Scheduled注解和TaskScheduler。当需要执行多线程定时任务时,ThreadPoolTaskScheduler是一个轻量级的解决方案。本文将通过一个具体的业务场景,介绍如何使用ThreadPoolTaskScheduler来实现多线程定时任务。
业务场景
假设我们需要开发一个电商平台,该平台需要定期执行以下任务:
-
库存检查:每天检查库存量,如果低于阈值,则自动触发补货。
-
订单审核:每小时审核新订单,自动确认有效订单。
这些任务需要并行执行,以提高效率。
实现步骤
1. 配置ThreadPoolTaskScheduler
首先,我们需要配置ThreadPoolTaskScheduler。在Spring Boot应用中,我们可以创建一个配置类来实现这一点。
java
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;@Configuration
@EnableScheduling
public class SchedulerConfig implements SchedulingConfigurer {@Overridepublic void configureTasks(ThreadPoolTaskScheduler taskScheduler) {taskScheduler.setPoolSize(10); // 设置线程池大小taskScheduler.setThreadNamePrefix("task-scheduler-");taskScheduler.initialize();}
}
2. 创建定时任务
接下来,我们创建具体的定时任务。我们将实现两个服务:InventoryCheckService和OrderAuditService。
java
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;@Service
public class InventoryCheckService {@Scheduled(cron = "0 0 1 * * ?") // 每天凌晨1点执行public void checkInventory() {System.out.println("执行库存检查任务");// 库存检查逻辑}
}
java
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;@Service
public class OrderAuditService {@Scheduled(cron = "0 0 * * * ?") // 每小时执行public void auditOrders() {System.out.println("执行订单审核任务");// 订单审核逻辑}
}
3. 多线程执行定时任务
为了使定时任务并行执行,我们可以在Scheduled注解中设置taskScheduler属性。
java
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class InventoryCheckService {@Autowiredprivate TaskScheduler taskScheduler;@Scheduled(cron = "0 0 1 * * ?", taskScheduler = "threadPoolTaskScheduler")public void checkInventory() {taskScheduler.execute(() -> {System.out.println("执行库存检查任务");// 库存检查逻辑});}
}
java
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;@Service
public class OrderAuditService {@Autowiredprivate TaskScheduler taskScheduler;@Scheduled(cron = "0 0 * * * ?", taskScheduler = "threadPoolTaskScheduler")public void auditOrders() {taskScheduler.execute(() -> {System.out.println("执行订单审核任务");// 订单审核逻辑});}
}
4. 启动定时任务
确保您的Spring Boot应用已经启用了定时任务的支持,通过在启动类上添加@EnableScheduling注解。
java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;@SpringBootApplication
@EnableScheduling
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}
}
异常处理
在处理定时任务中的异常情况时,确保系统稳定性的关键在于正确地捕获和处理这些异常。以下是一些最佳实践:
1. 使用try-catch块
确保每个定时任务都被try-catch块包裹,以便在任务执行过程中捕获任何未预料到的异常。
java
@Scheduled(fixedRate = 5000)
public void performTask() {try {// 任务逻辑} catch (Exception e) {// 异常处理逻辑logger.error("Error executing scheduled task", e);}
}
2. 记录异常
当异常发生时,记录异常信息对于调试和监控系统状态非常重要。
java
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class MyScheduledTask {private static final Logger logger = LoggerFactory.getLogger(MyScheduledTask.class);@Scheduled(cron = "0 * * * * *")public void scheduledTask() {try {// 任务逻辑} catch (Exception ex) {logger.error("Scheduled task failed", ex);}}
}
3. 重试机制
对于某些类型的错误,可以实施重试策略。例如,如果一个任务因为网络问题失败,可能在稍后重试时会成功。
java
@Scheduled(cron = "0 * * * * *")
public void scheduledTaskWithRetry() {try {// 任务逻辑} catch (TransientException te) {// 可以重试的异常scheduledTaskWithRetry(); // 重试逻辑} catch (Exception e) {// 非重试异常logger.error("Scheduled task failed", e);}
}
4. 错误隔离
如果可能,隔离可能导致异常的任务,以防止它们影响其他任务。
java
@Scheduled(cron = "0 * * * * *")
public void isolatedTask() {Thread taskThread = new Thread(() -> {try {// 任务逻辑} catch (Exception e) {logger.error("Isolated scheduled task failed", e);}});taskThread.setUncaughtExceptionHandler((thread, throwable) -> logger.error("Thread failed", throwable));taskThread.start();
}
5. 任务持久化
对于关键任务,可以考虑将任务持久化到数据库中,以便在系统崩溃后能够重新启动任务。
java
@Scheduled(cron = "0 * * * * *")
public void persistentTask() {try {// 任务逻辑} catch (Exception e) {logger.error("Persistent scheduled task failed", e);// 将任务状态标记为失败,并持久化}
}
6. 使用@Async进行异步处理
使用@Async注解将任务提交到Executor,这样可以异步处理任务,并避免阻塞主线程。
java
@Async
@Scheduled(cron = "0 * * * * *")
public void asyncScheduledTask() {try {// 任务逻辑} catch (Exception e) {logger.error("Async scheduled task failed", e);}
}
7. 超时机制
为任务设置合理的超时时间,防止某些任务长时间占用资源。
java
@Scheduled(cron = "0 * * * * *")
public void timedTask() {try {// 任务逻辑} catch (TimeoutException te) {logger.warn("Scheduled task timed out", te);}
}
8. 监控和报警
实现监控机制,当任务失败时触发报警,以便及时响应。
java
@Scheduled(cron = "0 * * * * *")
public void monitoredTask() {try {// 任务逻辑} catch (Exception e) {logger.error("Monitored scheduled task failed", e);// 发送报警}
}
9. 回滚机制
对于涉及事务的任务,确保在异常时能够进行回滚。
java
@Transactional
@Scheduled(cron = "0 * * * * *")
public void transactionalTask() {try {// 任务逻辑} catch (Exception e) {logger.error("Transactional scheduled task failed", e);// 事务回滚}
}
10. 错误恢复策略
制定错误恢复策略,比如重试、重置状态、通知管理员等。
java
@Scheduled(cron = "0 * * * * *")
public void recoveryTask() {try {// 任务逻辑} catch (Exception e) {recoverFromError(); // 自定义恢复逻辑}
}
通过实施上述策略,可以显著提高定时任务的稳定性和可靠性,确保系统在面对异常情况时能够保持稳定运行。
结论
通过使用ThreadPoolTaskScheduler,我们可以轻松地在Spring Boot应用中实现轻量级的多线程定时任务。这种方法不仅提高了任务执行的效率,而且使代码结构更加清晰。
相关文章:
Spring Boot中使用ThreadPoolTaskScheduler实现轻量级多线程定时任务
引言 在Java开发中,Spring Boot提供了多种方式来执行定时任务,如Scheduled注解和TaskScheduler。当需要执行多线程定时任务时,ThreadPoolTaskScheduler是一个轻量级的解决方案。本文将通过一个具体的业务场景,介绍如何使用Thread…...
完全二叉树的节点个数 C++ 简单问题
完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。 示例 1ÿ…...
每日一题学习笔记
给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。 如果可以,返回 true ;否则返回 false 。 magazine 中的每个字符只能在 ransomNote 中使用一次。 示例 1: 输入&#…...
从事人工智能学习Python还是学习C++?
人工智能(Artificial Intelligence,简称AI)是当今科技领域最热门的研究方向之一。AI 涉及多个学科和技术,特别是机器学习、神经网络、深度学习等技术的应用。在AI的开发过程中,编程语言的选择对于开发效率和项目实现至…...
博客摘录「 CNN中的感受野和有效感受野会对模型产生怎样的影响?」2024年9月29日
,中心像素受影响较大,离中心越远梯度信号越弱。梯度信号的衰减是指数级的,这意味着应用于感受野的大多数像素的梯度将是可忽略的(如果有的话)。 有效感受野的定义...
AURIX单片机示例:开发入门与点亮LED
文章目录 目的模板工程Blinky_LED示例链接总结 目的 这个例程比较简单,主要通过这个例程来介绍 AURIX™ Development Studio(ADS) 和 iLLD 库来开发 AURIX 系列单片机一些入门的内容。一些更为基础的资料等内容可以参考下面文章: 《英飞凌 AURIX TriCo…...
MySQL字符串函数与操作
在编程领域中,字符串操作是数据处理中至关重要的一部分。无论是文本分析、日志处理,还是格式化输出,字符串的操作技能都能极大提高工作效率。在 Python 中,字符串相关的函数和方法为开发者提供了强大的工具,帮助完成各种任务。了解如何灵活运用这些工具,能够有效提升编程…...
HTML+CSS 水滴登录页
文章目录 一、效果演示二、Code1.HTML2.CSS 三、实现思路拆分 一、效果演示 实现了一个水滴登录页的效果。页面包含一个水滴形状的登录框和两个按钮,登录框包括用户名、密码和登录按钮,按钮分别为忘记密码和注册。整个页面的设计非常有创意,采…...
基于Next.js和TailwindCss的TailwindCss
最近在研究 Next.js 和 TailwindCss ,这两天没事的时候就搞了一个 c。 目前工具部署在 Vercel ,欢迎各位体验(能提出意见更好嘿嘿) 体验地址: https://icon.999872.xyz/ 图片预览 👇...
若依开源系统多数据源整合clickhouse数据库详细步骤
1.添加依赖【pom.xml文件】 <!-- clickhouse数据源依赖--><dependency><groupId>ru.yandex.clickhouse</groupId>...
Subdominator:一款针对漏洞奖励计划的子域名安全枚举工具
关于Subdominator Subdominator是一款针对漏洞奖励计划的子域名安全枚举工具,可用于在漏洞搜寻和侦察过程中进行被动子域名枚举。它旨在通过高效枚举子域名和各种免费被动资源来帮助研究人员和网络安全专业人员发现潜在的安全漏洞。 Subdominator 与各种免费和付费…...
[leetcode]516_最长回文子序列
给你一个字符串 s ,找出其中最长的回文子序列,并返回该序列的长度。 子序列定义为:不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。示例 1: 输入:s "bbbab" 输出&a…...
电子相册|智能化电子相册|基于java的电子相册管理系统设计与实现(源码+数据库+文档)
电子相册管理系统 目录 基于java的电子相册管理系统设计与实现 一、前言 二、系统功能设计 三、系统实现 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取: 博主介绍:✌️大厂码农|毕设布道师&…...
linux项目_c语言:Makefile编写、动态库生成、添加动态库路径
一直想搞懂Linux中Makefile是怎么管理项目的,知识积累到一定程度后,我就做了一个自己的缩小项目去把剩下的细节搞清楚 代码: Service.c: #include <stdio.h> #include "lib_sevr.h" int main(){printf("输入a, b的值…...
Python学习(1):字典、DataFrame的创建方法
1. 字典的创建方法 1.1 直接创建 # 创建一个包含姓名和年龄的字典 person {"name": "Alice", "age": 25}print(person) # 输出:{name: Alice, age: 25} 1.2 使用 dict() 函数 # 使用键值对列表创建字典 person dict(name"…...
async await 介绍 从0手动实现async await
1 async await介绍 async 和 await 是用于处理异步编程的语法糖,它们简化了异步操作的编写,使其看起来像同步代码。通过 async 标记一个函数为异步函数,返回的是一个 Promise 对象,而 await 用来暂停执行,直到 Promise…...
UDP校验和计算及网络中的校验和机制
UDP (User Datagram Protocol) 是一种无连接的传输层协议,它不像 TCP 那样提供可靠的传输保证。虽然 UDP 不保证数据可靠性,但它仍然提供了一个可选的校验和机制来检测数据在传输过程中出现的错误。 理解UDP校验和的计算过程和其在网络中的作用至关重要。…...
如何使用C语言接入Doris数据库
如何使用C语言接入Doris数据库 一、环境准备1. 安装MySQL C API2. Doris数据库环境二、编写C语言接入代码1. 包含必要的头文件2. 编写连接和查询函数3. 编译和运行程序三、注意事项1. 安全性2. 错误处理3. 性能优化4. 兼容性5. 调试和日志记录四、结论Doris(之前称为Palo或Apa…...
DarkLabel 2.4 目标追标注工具介绍
DarkLabel介绍 https://github.com/darkpgmr/DarkLabel 官方地址 视频/图像标注工具,很适合用于目标追踪任务 DarkLabel可以在视频和图像中标注物体的边界框,并附上 ID 和name。还可以用于裁剪视频、从视频中采样训练图像以及对图像区域进行马赛克处理…...
uniapp设置从右上角到左下角的三种渐变颜色
推荐学习文档 golang应用级os框架,欢迎stargolang应用级os框架使用案例,欢迎star案例:基于golang开发的一款超有个性的旅游计划app经历golang实战大纲golang优秀开发常用开源库汇总想学习更多golang知识,这里有免费的golang学习笔…...
【网络】每天掌握一个Linux命令 - iftop
在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...
synchronized 学习
学习源: https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖,也要考虑性能问题(场景) 2.常见面试问题: sync出…...
五年级数学知识边界总结思考-下册
目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解:由来、作用与意义**一、知识点核心内容****二、知识点的由来:从生活实践到数学抽象****三、知识的作用:解决实际问题的工具****四、学习的意义:培养核心素养…...
土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等
🔍 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术,可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势,还能有效评价重大生态工程…...
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...
MySQL 8.0 事务全面讲解
以下是一个结合两次回答的 MySQL 8.0 事务全面讲解,涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容,并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念(ACID) 事务是…...
tomcat入门
1 tomcat 是什么 apache开发的web服务器可以为java web程序提供运行环境tomcat是一款高效,稳定,易于使用的web服务器tomcathttp服务器Servlet服务器 2 tomcat 目录介绍 -bin #存放tomcat的脚本 -conf #存放tomcat的配置文件 ---catalina.policy #to…...
从“安全密码”到测试体系:Gitee Test 赋能关键领域软件质量保障
关键领域软件测试的"安全密码":Gitee Test如何破解行业痛点 在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的"神经中枢"。从国防军工到能源电力,从金融交易到交通管控,这些关乎国计民生的关键领域…...
k8s从入门到放弃之HPA控制器
k8s从入门到放弃之HPA控制器 Kubernetes中的Horizontal Pod Autoscaler (HPA)控制器是一种用于自动扩展部署、副本集或复制控制器中Pod数量的机制。它可以根据观察到的CPU利用率(或其他自定义指标)来调整这些对象的规模,从而帮助应用程序在负…...
若依登录用户名和密码加密
/*** 获取公钥:前端用来密码加密* return*/GetMapping("/getPublicKey")public RSAUtil.RSAKeyPair getPublicKey() {return RSAUtil.rsaKeyPair();}新建RSAUti.Java package com.ruoyi.common.utils;import org.apache.commons.codec.binary.Base64; im…...
