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

共享线程池对@Scheduled定时任务的影响

最碰到一个监控任务偶发的执行时间漂移的问题,大概情况是:有自定义线程池tt,其他的异步任务使用@Async("tt"),监控的定时任务使用 @Scheduled@Async("tt"),如果异步任务高负载执行占满线程池,会不会影响定时任务?

先说答案:会的,绝对会影响。 在这种情况下,定时任务将无法保证准时执行,甚至可能出现严重延迟。

让我们来详细拆解一下这个过程,解释为什么会有影响。

执行流程分析

当您在一个方法上同时使用 @Scheduled@Async("tt") 时,Spring 的处理流程如下:

  1. 触发(Scheduling):

    • @Scheduled 注解的触发是由 Spring 内置的 ScheduledAnnotationBeanPostProcessor 处理的。
    • Spring 会创建一个专用的 ScheduledTaskRegistrar,它内部默认使用一个 ScheduledThreadPoolExecutor(例如核心线程数为 1)作为调度器(Scheduler)
    • 这个调度器的唯一职责就是像一个闹钟一样,在指定的时间点(如每分钟的第0秒)触发 @Scheduled 方法的执行。它不负责执行实际的任务逻辑。
  2. 执行(Execution):

    • 当“闹钟”响起的瞬间,调度器线程会发现一个 @Scheduled 任务需要运行。
    • 由于该方法上还有 @Async("tt") 注解,Spring 的异步代理拦截器会介入。它不会让调度器线程直接执行方法内容,而是将方法的实际执行包装成一个 Runnable提交到您指定的线程池 tt 中去排队等待。
    • 至此,调度器线程的职责就完成了,它立刻返回,准备触发下一个定时任务。它不关心任务 tt 中要多久才执行完。

为什么线程池 tt 满载会有影响?

理解了上面的流程,原因就非常清晰了:

  • 调度是准时的,执行是延迟的: 任务的“触发”非常准时,因为它由专用的调度线程池负责。但是,任务的“实际执行”完全依赖于您配置的线程池 tt
  • 线程池 tt 是瓶颈: 如果线程池 tt 被其他高并发、长时间运行的批处理任务完全占满(所有核心线程都在忙碌,且工作队列也已满),那么新提交的定时任务(作为一个 Runnable)只能tt 的队列中等待
  • 后果: 虽然系统每分钟都准时“喊了一声”该执行任务了,但这个“喊声”(即提交到 tt 队列的动作)被淹没在大量批处理任务中。定时任务必须等到 tt 线程池处理完它前面排队的批处理任务后,才能获得线程来执行自己。这导致了实际的业务逻辑执行时间严重滞后。

举个例子:
假设您有一个 @Scheduled(cron = "0 * * * * *") + @Async("tt") 的任务,希望每分钟执行一次。

  • 00:00:00: 调度器准时触发,任务被提交到 tt 的队列尾部。
  • 但此时 tt 队列中有100个批处理任务,每个耗时2秒。
  • 您的定时任务必须等待 100 * 2s / nThreads 的时间后才能真正开始执行。
  • 可能直到 00:03:20 它才跑起来,而此时调度器已经在 00:01:0000:02:00 又触发了两次,导致了任务的堆积(Backlog)。这是非常严重的问题。

结论与最佳实践

您的这种配置方式,实际上是将任务的调度执行分离开了,这本身是一种常见的模式。但问题在于执行资源的分配上。

最佳实践仍然是:隔离资源(线程池隔离)。

  1. 为不同类型的任务使用专用的线程池:

    • 定时任务执行池: 为所有通过 @Scheduled + @Async 执行的定时任务单独创建一个线程池(例如 scheduledExecutor)。可以根据定时任务的数量和特性来配置大小(例如 corePoolSize = 5)。
    • 批处理任务池: 其他的批处理任务使用另一个线程池(例如 batchExecutor)。
    @Configuration
    @EnableScheduling
    @EnableAsync
    public class AsyncConfig {// 专用于执行定时任务的线程池@Bean("scheduledExecutor")public Executor scheduledExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(5);executor.setThreadNamePrefix("scheduled-exec-");executor.initialize();return executor;}// 专用于高并发批处理的线程池@Bean("batchExecutor") // 名字tt改为更有意义的batchExecutorpublic Executor batchExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(20);executor.setMaxPoolSize(50);executor.setQueueCapacity(200);executor.setThreadNamePrefix("batch-exec-");executor.initialize();return executor;}
    }
    
  2. 在注解中明确指定不同的执行器:

    • 定时任务方法指定使用 scheduledExecutor
    • 批处理任务方法(可能是通过API调用触发)指定使用 batchExecutor
    // 定时任务
    @Scheduled(cron = "0 * * * * *")
    @Async("scheduledExecutor") // 指定使用专用的执行池
    public void myScheduledTask() {// ... 任务逻辑
    }// 批处理Service中的方法
    @Async("batchExecutor") // 指定使用批处理池
    public void someBatchProcess() {// ... 批处理逻辑
    }
    

总结: 永远不要让对实时性要求高的定时任务执行,去和后台批处理任务争夺同一组线程资源。通过资源隔离,您的定时任务才能得到准时执行。


文章转载自:

http://yJICatMb.znknj.cn
http://Z5Q4rL2l.znknj.cn
http://t9fBqis4.znknj.cn
http://lnZy3Q9n.znknj.cn
http://vbgsc5t0.znknj.cn
http://9wQadWUd.znknj.cn
http://lov8eYPp.znknj.cn
http://W1UdC7nZ.znknj.cn
http://q1GvkLGl.znknj.cn
http://ozwPDMzn.znknj.cn
http://yw1qKcUK.znknj.cn
http://G95Vxeve.znknj.cn
http://GNG85QiM.znknj.cn
http://rfUquIgU.znknj.cn
http://yEVOkqZ0.znknj.cn
http://RahyVOH7.znknj.cn
http://vYgKC7sA.znknj.cn
http://IBZRhCuj.znknj.cn
http://Ocal4DkU.znknj.cn
http://cVZkcM0t.znknj.cn
http://Pqxy4sqF.znknj.cn
http://rKVYbnGB.znknj.cn
http://QdlRR1bu.znknj.cn
http://VU8Pj2wm.znknj.cn
http://LwuzSUkz.znknj.cn
http://ROmf6oOX.znknj.cn
http://FoLzFjbB.znknj.cn
http://Vb6fGsig.znknj.cn
http://jyByijpr.znknj.cn
http://z0KNSfyW.znknj.cn
http://www.dtcms.com/a/369078.html

相关文章:

  • 一张图看懂AI时代后端系统架构
  • 人工智能学习:什么是GRU模型
  • 高效管理网络段和端口集合的工具之ipset
  • 为什么要用VR全景?5个答案告诉你
  • 【Linux学习笔记】信号的深入理解之软件条件产生信号
  • 前端事件循环:代码世界的“排队”艺术!
  • JP4-7-MyLesson后台前端(一)
  • PPIO上线kimi-k2-0905,编码能力大幅提升
  • UniApp 页面通讯方案全解析:从 API 到状态管理的最佳实践
  • 嵌入式|Linux中打开视频流的两种方式V4l2和opencv
  • VBA 中的 Excel 工作表函数
  • Unix/Linux 平台通过 IP 地址获取接口名的 C++ 实现
  • EXCEL列数据前面补零
  • Big Data Analysis
  • 拿到一组数据在mars3d上渲染报错排查思路
  • 力扣hot100:搜索二维矩阵 II(常见误区与高效解法详解)(240)
  • 《从报错到运行:STM32G4 工程在 Keil 中的头文件配置与调试实战》
  • Meta AI眼镜Hypernova量产临近,微美全息构筑护城河引领人机交互变革浪潮
  • SQL表一共有几种写入方式
  • Vue3源码reactivity响应式篇之ReactiveEffect类
  • C++中的Reactor和Proactor模型进行系统性解析
  • 调试技巧:Chrome DevTools 与 Node.js Inspector
  • 双碳目标下的24小时分时综合能源系统低碳优化调度:基于 Matlab/YALMIP/CPLEX的方法与仿真
  • 告别 “无效阅读”!2025 开学季超赞科技书单,带孩子解锁 AI、编程新技能
  • 鸿蒙Next的UI国际化与无障碍适老化实践:构建全球包容的数字世界
  • react 全屏页面自适应操作,注意问题
  • 计算机毕设选题:基于Python数据挖掘的高考志愿推荐系统
  • PCL中的特征提取
  • 2025年TOP8最佳GNSS位移监测设备权威推荐榜单
  • 告别研发内耗!这款免费项目管理工具,让团队效率实现 3 倍跃升