当前位置: 首页 > article >正文

基于自定义线程池手写一个异步任务管理器

我们在后端执行某些耗时逻辑操作时往往会导致长时间的线程阻塞,在这种情况之下,我们往往会引一条异步线程去处理这些异步任务,如果每次都创建新的线程来处理这些任务,不仅会增加代码冗余,还可能造成线程管理混乱,影响系统性能。在我们的Spring框架中是自带异步任务处理机制的,比如我们使用@Async 注解可以处理一些简单的异步任务,但这样确实无法精确去控制线程池资源,也无法灵活去管理任务调度,由此,我们可以去自行设计一个高效的自定义异步任务管理器去统一调度处理我们的自定义任务。

1.前置配置

自定义线程池,并将其注册到IOC容器中

 /*** 自定义线程池配置* @Author GuihaoLv**/
@Configuration
public class ThreadPoolConfig
{// 核心线程池大小private int corePoolSize = 50;// 最大可创建的线程数private int maxPoolSize = 200;// 队列最大长度private int queueCapacity = 1000;// 线程池维护线程所允许的空闲时间private int keepAliveSeconds = 300;/*** 通用任务线程池* @return*/@Bean(name = "threadPoolTaskExecutor")public ThreadPoolTaskExecutor threadPoolTaskExecutor(){ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setMaxPoolSize(maxPoolSize);executor.setCorePoolSize(corePoolSize);executor.setQueueCapacity(queueCapacity);executor.setKeepAliveSeconds(keepAliveSeconds);// 线程池对拒绝任务(无线程可用)的处理策略//当线程池满了,新任务无法加入时,CallerRunsPolicy 让提交任务的线程(即调用方线程)直接执行该任务,// 而不是丢弃或抛出异常,从而保证任务不会丢失。executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());return executor;}/*** 执行周期性或定时任务*/@Bean(name = "scheduledExecutorService")protected ScheduledExecutorService scheduledExecutorService(){//这里没有最大线程数的概念,所有线程都属于核心线程。return new ScheduledThreadPoolExecutor(corePoolSize,new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d") //设置线程名称,方便排查日志。.daemon(true).build(), //daemon(true) 使线程池中的线程成为 守护线程,即 JVM 退出时不会阻止进程终止。new ThreadPoolExecutor.CallerRunsPolicy()) //使用 CallerRunsPolicy,避免任务丢失。{//任务执行完毕后,调用 Threads.printException(r, t),捕获并记录异常,确保线程池不会因为未捕获的异常而崩溃。@Overrideprotected void afterExecute(Runnable r, Throwable t){super.afterExecute(r, t);Threads.printException(r, t);}};}
}

2.异步任务管理器配置

 /*** 异步任务管理器* AsyncManager 是 整个异步任务调度的核心,它提供了 任务执行、调度和管理。* @Author GuihaoLv*/
public class AsyncManager
{/*** 操作延迟10毫秒*/private final int OPERATE_DELAY_TIME = 10;/*** 异步操作任务调度线程池* executor 采用 ScheduledExecutorService 线程池,可以 定时执行异步任务,提高并发能力*/private ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService");/*** 单例模式* 采用 单例模式,确保全局只有一个 AsyncManager 实例,保证任务调度统一管理。创建单例对象*/private AsyncManager(){}//创建异步任务管理器的静态对象private static AsyncManager me = new AsyncManager();public static AsyncManager me(){return me;}/*** 使用调度线程池执行任务* @param task 任务*///TimerTask是Java编程语言中的一个抽象类,通常用于安排将来某个时间执行的任务,或者以固定的速率重复执行的任务。// 它是与Timer类一起使用的,Timer负责管理和调度这些任务。public void execute(TimerTask task){executor.schedule(task, OPERATE_DELAY_TIME, TimeUnit.MILLISECONDS);}/*** 停止任务线程池*/public void shutdown(){//优雅关闭线程池Threads.shutdownAndAwaitTermination(executor);}
}
 /*** 确保应用退出时能关闭后台线程* @Author GuihaoLv*/
@Component
public class ShutdownManager
{private static final Logger logger = LoggerFactory.getLogger("sys-user");@PreDestroy //它用于在 Spring Bean 被销毁前执行清理逻辑。public void destroy(){shutdownAsyncManager();HttpUtils.shutdown();}/*** 停止异步执行任务*/private void shutdownAsyncManager(){try{logger.info("====关闭后台任务任务线程池====");AsyncManager.me().shutdown();}catch (Exception e){logger.error(e.getMessage(), e);}}}

3.异步工厂配置,将异步任务的启动逻辑都扔到异步工厂中处理

/*** 异步工厂(产生任务用)* AsyncFactory 主要用于创建异步任务,它相当于一个 "任务工厂",* 可以根据不同的需求创建不同的任务(如记录用户登录信息、记录操作日志)。** @Author GuihaoLv*/
public class AsyncFactory
{private static final Logger sys_user_logger = LoggerFactory.getLogger("sys-user");// 定义任务:计算热点文章public static TimerTask calculateHotArticlesTask() {return new TimerTask() {@Overridepublic void run() {try {// 获取 HotArticleAsycTask 实例HotArticleAsycTask hotArticleAsycTask = SpringUtils.getBean(HotArticleAsycTask.class);// 执行热点文章计算任务hotArticleAsycTask.calculateHotArticles();} catch (Exception e) {sys_user_logger.error("计算热点文章失败", e);}}};}// 定义任务:定时热搜清理public static TimerTask cleanupOldKeywords() {return new TimerTask() {@Overridepublic void run() {try {// 获取 HotArticleAsycTask 实例HotSearchCleanupTask hotArticleAsycTask = SpringUtils.getBean(HotSearchCleanupTask.class);// 执行热点文章计算任务hotArticleAsycTask.cleanupOldKeywords();} catch (Exception e) {sys_user_logger.error("清理热搜失败", e);}}};}
}

4.调用异步工厂中的逻辑

/*** 热点文章实时计算* @Author GuihaoLv*/
@Component
public class HotArticleAsycTask {@Autowiredprivate StringRedisTemplate redisTemplate;private static final String LIKES_KEY = "blog:likes";private static final String FAVORITES_KEY = "blog:favorites";private static final String HOT_ARTICLES_KEY = "blog:hot"; // 存热点文章public void calculateHotArticles() {Set<String> blogIds = redisTemplate.opsForZSet().range(LIKES_KEY, 0, -1);if (blogIds == null || blogIds.isEmpty()) return;for (String blogId : blogIds) {Double likes = redisTemplate.opsForZSet().score(LIKES_KEY, blogId);Double favorites = redisTemplate.opsForZSet().score(FAVORITES_KEY, blogId);// 计算热度double hotScore = (likes != null ? likes * 5.0 : 0) +(favorites != null ? favorites * 8.0 : 0);// 热度超过阈值 500,加入热点文章if (hotScore >= 500) {redisTemplate.opsForZSet().add(HOT_ARTICLES_KEY, blogId, hotScore);System.out.println("🔥 文章 " + blogId + " 进入热点榜,热度:" + hotScore);}}}/*** 每 5 分钟执行一次的定时任务*/@Scheduled(fixedRate = 100000) // 每 5 分钟执行一次public void scheduleHotArticlesCalculation() {// 将任务交给异步任务管理器执行AsyncManager.me().execute(AsyncFactory.calculateHotArticlesTask());}
}

相关文章:

基于自定义线程池手写一个异步任务管理器

我们在后端执行某些耗时逻辑操作时往往会导致长时间的线程阻塞&#xff0c;在这种情况之下&#xff0c;我们往往会引一条异步线程去处理这些异步任务&#xff0c;如果每次都创建新的线程来处理这些任务&#xff0c;不仅会增加代码冗余&#xff0c;还可能造成线程管理混乱&#…...

sql靶场-时间盲注(第九、十关)保姆级教程

目录 时间盲注&#xff08;第九、十关&#xff09; 1.判断 2.确认时间盲注 2.手工尝试时间盲注 数据库名长度 数据库名字符 表数 表名长度 表名字符 字段数 字段名长度 字段名字符 4.脚本时间盲注注入 5.第十关 时间盲注&#xff08;第九、十关&#xff09; 1.判…...

Vuex 高级技巧与最佳实践

使用 map 辅助函数简化代码&#xff1a; javascript import { mapState, mapGetters } from vuexexport default {computed: {...mapState([num]),...mapGetters([doubleNum])} }模块化开发&#xff1a; javascript // modules/student.js export default {namespaced: true,st…...

51c自动驾驶~合集54

我自己的原文哦~ https://blog.51cto.com/whaosoft/13517811 #Chameleon 快慢双系统&#xff01;清华&博世最新&#xff1a;无需训练即可解决复杂道路拓扑 在自动驾驶技术中&#xff0c;车道拓扑提取是实现无地图导航的核心任务之一。它要求系统不仅能检测出车道和交…...

大模型推理:LM Studio在Mac上部署Deepseek-R1模型

LM Studio LM Studio是一款支持离线大模型部署的推理服务框架&#xff0c;提供了易用的大模型部署web框架&#xff0c;支持Linux、Mac、Windows等平台&#xff0c;并提供了OpenAI兼容的SDK接口&#xff0c;主要使用LLama.cpp和MLX推理后端&#xff0c;在Mac上部署时选择MLX推理…...

扩散模型:AIGC领域的核心引擎,解锁图像生成新维度

一、扩散模型技术原理 扩散模型是一类生成模型&#xff0c;它运用了物理热力学中的扩散思想&#xff0c; 主要包括前向扩散和反向扩散两个过程。 1.1、生成模型 在深度学习中&#xff0c;生成模型的目标是根据给定的样本&#xff08;训练数据&#xff09; 生成新样本。首先给…...

Java多线程与高并发专题——原子类和 volatile、synchronized 有什么异同?

原子类和 volatile异同 首先&#xff0c;通过我们对原子类和的了解&#xff0c;原子类和volatile 都能保证多线程环境下的数据可见性。在多线程程序中&#xff0c;每个线程都有自己的工作内存&#xff0c;当多个线程访问共享变量时&#xff0c;可能会出现一个线程修改了共享变…...

//要求:将输入的字符串中的数字转换为罗马数字,长度小于9(运用方法:Switch方法)

import java.util.Scanner;public class Num2 {public static void main(String[] args){ // I II III IV V VI VII VIII IX//要求&#xff1a;将输入的字符串中的数字转换为罗马数字,长度小于9&#xff08;运用方法&#xff1a;查表法&#xff09;//1输入数字//2有效字符判断/…...

【数据结构】数据结构,算法 概念

0.本篇问题&#xff1a; 数据、数据元素、数据对象、数据项之间的基本关系&#xff1f;ADT是什么&#xff1f;数据结构的三要素&#xff1f;数据的逻辑结构有哪些&#xff1f;数据的存储结构有哪些&#xff1f;算法的五个特征&#xff1f;O(1) O(logn) O(n^n) O(n) O(n^2…...

pytest 框架学习总结

视频&#xff1a;pytest01-快速上手_哔哩哔哩_bilibili 资料&#xff1a;pytest 框架 - 白月黑羽 基于 Python 语言的自动化测试框架 最知名的 有如下 3 款unittest、pytest、robotframework 前两款框架主要&#xff08;或者说很大程度上&#xff09;是 聚焦 在 白盒单元测试…...

总结 HTTP 协议的基本格式, 相关知识以及抓包工具fiddler的使用

目录 1 HTTP是什么 2 HTTP协议格式 3 HTTP请求(Request) 3.1 认识URL 3.2 方法 3.3 认识请求"报头"(header) 4 HTTP响应详解 4.1 认识"状态码"(statuscode) 4.2 认识响应"报头"(header) 4.3 认识响应"正⽂"(body) 5 通过f…...

python中的max(),需要注意的点

words ["apple", "banana", "grape", "cherry"] 对每个单词&#xff0c;keylambda x: len(x) 会计算它的长度&#xff1a; "apple" 长度是 5"banana" 长度是 6"grape" 长度是 5"cherry" 长度…...

DeepSeek-R1大模型微调技术深度解析:架构、方法与应用全解析

1. DeepSeek-R1大模型架构设计与技术特性 1.1 架构设计 DeepSeek-R1作为超大规模语言模型,其核心架构设计包含以下创新: 专家混合架构(MoE) 采用6710亿参数的混合专家架构(MoE),每个推理过程仅激活370亿参数,实现计算效率与资源利用率的突破性提升。 Transformer框架…...

探索Maas平台与阿里 QWQ 技术:AI调参的魔法世界

摘要&#xff1a;本文介绍了蓝耘 Maas 平台在人工智能领域的表现及其核心优势&#xff0c;包括强大的模型支持、高效的资源调度和友好的操作界面。文章还探讨了蓝耘 Maas 平台与阿里 QWQ 技术的融合亮点及应用拓展实例&#xff0c;并提供了调参实战指南&#xff0c;最后对蓝耘 …...

Linux第三次练习

1、创建根目录结构中的所有的普通文件 首先在根目录下面新创建一个test目录&#xff0c;然后将查找到的普通文件新建到test目录下 2、列出所有账号的账号名 3、将/etc/passwd中内容按照冒号隔开的第三个字符从大到小排序后输出所有内容 4、列出/etc/passwd中的第20行-25行内容…...

软件测试知识总结

1、黑盒测试、白盒测试、灰盒测试 1.1 黑盒测试 黑盒测试又叫功能测试、数据驱动测试 或 基于需求规格说明书的功能测试。该类测试注重于测试软件的功能性需求。 采用这种测试方法&#xff0c;测试工程师把测试对象看作一个黑盒子&#xff0c;完全不考虑程序内部的逻辑结构和…...

JConsole 监控线程池状态

JConsole 可以用来监控 Java 线程池&#xff08;ThreadPoolExecutor&#xff09;的状态&#xff0c;包括线程数量、任务执行情况、CPU 及内存使用情况等。下面是具体的操作步骤&#xff1a; 一、启动 JConsole 1. 启动 JConsole Windows&#xff1a;在 JDK bin 目录下找到 j…...

【HTML】三、表单与布局标签

文章目录 1、input1.1 input的占位文案1.2 单选框1.3 上传文件1.4 多选框 2、 下拉菜单3、文本域&#xff1a;多行输入4、label标签&#xff1a;说明与增大点击范围5、按钮与form表单6、无语义布局标签7、有语义的布局标签8、字符实体9、练习&#xff1a;注册页面 1、input in…...

OpenBMC:BmcWeb添加路由1 getParameterTag

BmcWeb对于路由的设计其实是参考了Crow BMCWEB_ROUTE(app, "/upload/image/<str>").privileges({{"ConfigureComponents", "ConfigureManager"}}).methods(boost::beast::http::verb::post, boost::beast::http::verb::put)([](const cro…...

【结构设计】3D打印创想三维Ender 3 v2

【结构设计】3D打印创想三维Ender 3 v2 文章目录 前言一、Creality Slicer1.2.3打印参数设置二、配件更换1.捆扎绑扎线2.气动接头3D打印机配件插头3.3D打印机配件Ender3pro/V2喷头套件4.读卡器 TF卡5.micro sd卡 三、调平四、参考文章总结 前言 使用工具&#xff1a; 1.创想三…...

嵌入式web服务器实现上传下载储存研究

标题:嵌入式web服务器实现上传下载储存研究 内容:1.摘要 随着互联网与嵌入式系统的不断融合&#xff0c;嵌入式设备对数据上传、下载及储存功能的需求日益增长。本文旨在研究嵌入式web服务器实现上传、下载和储存功能的有效方法。通过分析常见的嵌入式web服务器架构&#xff0…...

UE小:UE5.5 PixelStreamingInfrastructure 使用时注意事项

1、鼠标默认显示 player.ts中的Config中添加HoveringMouse:true 然后运行typescript\package.json中的"build":npx webpack --config webpack.prod.js...

Anaconda 入门指南

Anaconda 入门指南 一、下载安装 Anaconda 1、下载地址&#xff1a;Anaconda 推荐下载 python3 版本, 毕竟未来 python2 是要停止维护的。 2、安装 Anaconda 按照安装程序提示一步步安装就好了, 安装完成之后会多几个应用&#xff1a; Anaconda Navigtor &#xff1a;用于管…...

web组态可视化编辑器

Web组态可视化编辑器是一种用于创建和配置工业自动化、物联网&#xff08;IoT&#xff09;和智能建筑等领域的图形化用户界面&#xff08;GUI&#xff09;的工具。它允许用户通过拖放组件、配置参数和连接数据源来设计和部署实时监控和控制界面。以下是一些常见的Web组态可视化…...

CTA重建:脑血管重建,CT三维重建,三维建模 技术,实现

CTA&#xff08;CT血管造影&#xff09;是一种基于CT扫描的医学成像技术&#xff0c;主要用于血管系统的三维重建和可视化。脑血管重建是CTA的重要应用之一&#xff0c;能够帮助医生诊断脑血管疾病&#xff08;如动脉瘤、狭窄、畸形等&#xff09;。以下是实现CTA脑血管重建、C…...

Ollama+OpenWebUI本地部署大模型

OllamaOpenWebUI本地部署大模型 前言Ollama使用Ollama安装Ollama修改配置Ollama 拉取远程大模型Ollama 构建本地大模型Ollama 运行本地模型&#xff1a;命令行交互Api调用Web 端调用 总结 前言 Ollama是一个开源项目&#xff0c;用于在本地计算机上运行大型语言模型&#xff0…...

如何打包数据库mysql数据,并上传到虚拟机上进行部署?

1.连接数据库&#xff0c;使得我们能看到数据库信息&#xff0c;才能进行打包上传 2. 3. 导出结果如下&#xff0c;是xml文件 4.可以查询每个xml文件的属性&#xff0c;确保有大小&#xff0c;这样才是真实导出 5跟着黑马&#xff0c;新建文件夹&#xff0c;并且把对应的东西放…...

Vue 自定义指令深度解析与应用实践

文章目录 1. 自定义指令概述1.1 核心概念1.2 指令生命周期 2. 自定义指令基础2.1 指令注册2.2 指令使用 3. 指令钩子函数详解3.1 钩子函数参数3.2 钩子函数示例 4. 自定义指令应用场景4.1 表单自动聚焦4.2 权限控制4.3 图片懒加载 5. 高级应用技巧5.1 动态指令参数5.2 指令修饰…...

Vue中有什么组件可以实现轮播效果,每次出现四个元素?

在 Vue 中实现「每次显示四个元素」的轮播效果&#xff0c;可以通过以下组件实现&#xff08;推荐按优先级排序&#xff09;&#xff1a; 1. Swiper Vue-Awesome-Swiper&#xff08;推荐&#xff09; 特点&#xff1a; 最成熟的轮播库&#xff0c;支持复杂交互&#xff08;触…...

Doris表的分区数量保持在多少范围内性能是最好的

在 Apache Doris 中&#xff0c;分区数量的最佳范围需结合数据规模、查询模式及集群资源动态调整&#xff0c;以下是根据最新版本&#xff08;2025年&#xff09;的实践总结和官方建议&#xff1a; 1. 分区数量与数据量的平衡原则 • 单分区数据量建议&#xff1a;每个分区的数…...