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学习笔…...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...
无法与IP建立连接,未能下载VSCode服务器
如题,在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈,发现是VSCode版本自动更新惹的祸!!! 在VSCode的帮助->关于这里发现前几天VSCode自动更新了,我的版本号变成了1.100.3 才导致了远程连接出…...
2.Vue编写一个app
1.src中重要的组成 1.1main.ts // 引入createApp用于创建应用 import { createApp } from "vue"; // 引用App根组件 import App from ./App.vue;createApp(App).mount(#app)1.2 App.vue 其中要写三种标签 <template> <!--html--> </template>…...
大语言模型如何处理长文本?常用文本分割技术详解
为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...
智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...
《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...
三体问题详解
从物理学角度,三体问题之所以不稳定,是因为三个天体在万有引力作用下相互作用,形成一个非线性耦合系统。我们可以从牛顿经典力学出发,列出具体的运动方程,并说明为何这个系统本质上是混沌的,无法得到一般解…...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...
AI,如何重构理解、匹配与决策?
AI 时代,我们如何理解消费? 作者|王彬 封面|Unplash 人们通过信息理解世界。 曾几何时,PC 与移动互联网重塑了人们的购物路径:信息变得唾手可得,商品决策变得高度依赖内容。 但 AI 时代的来…...
