Spring @Scheduled @Async联合实现调度任务

2023-11-05

定时任务之前一直用的是quartz之类,但是注意到Spring中其实也提供了一种简单的调度注释@Scheduled,也就想尝一下鲜..

代码示意如下:

复制代码

@Component
@EnableScheduling
public class AsyncTaskHandlerTask {

    @Scheduled(fixedDelay = 1000)
    public void task1() {
         //输出日志
    }

    @Scheduled(fixedDelay = 1000)
    public void task2() {
         //输出日志    
    }
}

复制代码

执行了一下,完全ok,日志打印正常,2个任务也都正常定时执行了.那好,添加些业务逻辑进去:

复制代码

@Component
@EnableScheduling
public class AsyncTaskHandlerTask {

    @Scheduled(fixedDelay = 1000)
    public void task1() {
         while(true){
            ....
         }
    }

    @Scheduled(fixedDelay = 1000)
    public void task2() {
         while(true){
            ....
         }
     }

}

复制代码

再启动,咦,奇怪了,怎么定时任务没有执行呢?倘使我之前没有输出日志试验,我可能就认为注解的用法错了呢...重新添加日志,下断点重跟了一下启动过程发现:

程序进入到while死循环后就卡死了,没有再继续启动另一个定时任务了.通过现象可知@Scheduled启动过程是一个单线程同步启动过程,故一旦中途被阻塞,会导致整个启动过程阻塞,

其余的定时任务都不会启动.这明显很奇怪,网上的教程大多数是xml配置形式,Spring的官网我这头打开又奇慢无比..但是从xml的配置形式可知需要配置一个线程池来启动定时任

务.但是Javaconfig形式的则没有说明.但是我查询到了另一个注解@Async,这个异步注解我是使用过的,可以指定线程池,打到方法上后便会以指定的线程池来执行方法.然后解决方案来了:

复制代码

@Component
@EnableScheduling
public class AsyncTaskHandlerTask {

    @Scheduled(fixedDelay = 1000)
    @Async
    public void task1() {
         while(true){
            ....
         }
    }

    @Scheduled(fixedDelay = 1000)
    @Async
    public void task2() {
         while(true){
            ....
         }
     }

}

复制代码

再次启动,不会再被阻塞.

2017-11-28更新:

本来以为找到了正解,结果证明是误入了歧途..以上是完全错误的使用,虽然看起来貌似是正确的..正应了一句话啊,啥都不如看源码啊...

太懒了,本来这个应该再单独开个文章再说的,但是太懒了...

进入正题,按照如上实现部署后突然发现一个诡异的问题,定时任务发生了异常的"阻塞"现象,某个任务突然看起来不再执行了,直接卡死了.第一印象是死锁了,直接jstack生成了一份堆栈信息,仔细分析后发现一个诡异问题,定时任务并没有像Scheduled定义的那样一次结束后再执行下一次,而是并发执行多次,直接将Async定义的线程池跑满.那么问题也就好解释了,Async注解后,直接异步在新线程中执行任务,由于异步执行Scheduled认为上一次已经执行完马上开始执行下一次,导致不停执行定时任务直接跑满Async使用的线程池.那么这实际上是一种错误的使用方法..怎么办?

只好点了@EnableScheduling注解看一下源码中怎么说的吧.

 

* <p>When more control is desired, a {@code @Configuration} class may implement
 * {@link SchedulingConfigurer}. This allows access to the underlying
 * {@link ScheduledTaskRegistrar} instance. For example, the following example
 * demonstrates how to customize the {@link Executor} used to execute scheduled
 * tasks:

 

实际上已经说的很明白了,更多的控制,只需要继承 SchedulingConfigurer 这个类,之前没有找到对应xml中配置线程池的方法也正是如此.

复制代码

 * public class AppConfig implements SchedulingConfigurer {
 *
 *     @Override
 *     public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
 *         taskRegistrar.setScheduler(taskExecutor());
 *     }
 *
 *     @Bean(destroyMethod="shutdown")
 *     public Executor taskExecutor() {
 *         return Executors.newScheduledThreadPool(100);
 *     }
 * }

复制代码

标红处就是使用线程池的配置,之后再执行不仅以多线程来启动定时任务,而且也不会出现定时任务重复并发执行的问题.至此此问题圆满解决.再感叹下啥都不如看源码.

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring @Scheduled @Async联合实现调度任务 的相关文章

随机推荐

  • DSTC10 赛道最佳论文揭晓 文心 PLATO 再获殊荣

    国际对话系统技术挑战赛DSTC The Dialog System Technology Challenge 作为全球人工智能顶级学术竞赛 由微软 卡内基梅隆大学的科学家于2013年发起 在对话领域具有极高的权威性和知名度 近日 第十届对话
  • C++ Primer Plus(第6版) 复习题汇总

    目录 10 对象和类 1 什么是类 2 类如何实现抽象 封装和数据隐藏 3 对象和类之间的关系 4 除了是函数之外 类函数成员与类数据成员之间的区别是什么 5 定义一个类来表示银行帐户 7 给出复习题5中的银行账户类的构造函数的代码 8 什
  • 2.26—— 问题 B: 回文日期

    题目描述 在日常生活中 通过年 月 日这三个要素可以表示出一个唯一确定的日期 牛牛习惯用8位数字表示一个日期 其中 前4位代表年份 接下来2位代表月份 最后2位代表日期 显然 一个日期只有一种表示方法 而两个不同的日期的表示方法不会相同 牛
  • 西米支付:支付二维码的简单介绍

    二维码支付从1 0到3 0时代的历史进程 实际上二维码技术被推出来已经有十多年了 这段悠久绵长的英雄无用武之地的时代属于二维码1 0时代 得益于互联网电子商务的飞速发展首先将二维码应用于支付并发扬光大的是两个第三方支付公司 支付宝 微信 这
  • 短作业优先调度算法C语言实现

    实验原理 短进程优先算法是以作业的长短来计算优先级 作业越短 其优先级越高 作业的长短是以作业所要求的运行时间来衡量的 在把短作业优先调度算法用于作业调度时 它将从外存的作业后备队列中选择若干个估计运行时间最短的作业 优先将它们调入内存运行
  • 类com.lu.servlet.HelloServlet不是Servlet

    tomcat10之后servlet依赖包名不是javax servlet 而是jakarta servlet 可以用以下两个依赖
  • vue当用户单击任何按钮时,只将该值设置为true,其他值为false

    最近在做卡片切换时遇到这样的问题 场景 当点击A时显示A的相关卡片信息 点击B时显示B的相关卡片信息 以此类推 思路 定义一个卡片状态对象 isCardState A false 利用点击按钮传item值做判断 如果相等显示即可 问题 点击
  • 如何创建美观的邮件模板并通过qq邮箱的SMTP服务向用户发送

    最近在写注册功能的自动发送邮箱告知验证码的功能 无奈根本没有学过前端 只有写Qt的qss基础 只好借助网页设计自己想要的邮箱格式 最终效果如下 也推销一下自己的项目ShaderLab 可运行ShaderToy上的大部分着色器代码 有学图形学
  • Spell 基于最长公共子序列的在线日志解析方法

    文章目录 01 日志模板挖掘 02 基于 LCS 的日志解析流程 2 1 日志键匹配查找 2 2 拆分与合并处理 2 2 1 拆分过程 2 2 2 合并过程 03 匹配查找优化 3 1 前缀树预过滤 3 2 倒排索引查找 04 Spell
  • APP弱网测试

    APP弱网测试 一 网络测试的一般流程 step1 首先要考虑网络正常的情况 各个模块的功能正常可用 页面元素 数据显示正常 step2 其次要考虑无网络的情况 APP各个功能在无网络情况下是否可用 APP各个页面之间切换是否正常 发送网络
  • torch.nn.Module和torch.nn.LSTM 相关文档

    torch nn Module和torch nn LSTM 相关文档 搬运官方链接 class torch nn Module 所有网络的基类 你的模型也应该继承这个类 import torch nn as nn import torch
  • fatal error C1034: stdio.h: 不包括路径集 ---LINK : fatal error LNK1104: 无法打开文件“libucrt.lib”【已解决】

    用windows 自带的编译工具 cl exe 编译 链接程序时候报错如下 1 编译报错 1 cpp 1 fatal error C1034 stdio h 不包括路径集 解决方法 新建环境变量 变量名 INCLUDE 变量值 D vs20
  • MQ 消息丢失、重复、积压问题,如何解决?

    MQ是面试中比较高频的问题 下面分享下MQ的常见问题 面试官在面试候选人时 如果发现候选人的简历中写了在项目中使用了 MQ 技术 如 Kafka RabbitMQ RocketMQ 基本都会抛出一个问题 在使用 MQ 的时候 怎么确保消息
  • Objective-C非正式协议和分类的区别

    当一个项目需要使用到一些通用的方法 这些方法需要在多个类中使用 那么我们就可以使用非正式协议来定义这些方法 以便于多个类之间共享这些方法 比如 我们可以定义一个名为 Utilities 的非正式协议 并在其中定义一些通用的方法 比如 Uti
  • 最大熵模型

    1 什么是最大熵原理 例子1 假设随机变量X有5个取值 A B C D E 要估计各个值的概率P A P B P E 这些概率值满足条件P A P B P C P D P E 1 但是满足这个条件的概率分布有无数个 如果没有其他信息 一个可
  • vue项目打包及配置跨域

    一 配置 proxy 跨域 module exports devServer open true 自动启动浏览器 host localhost localhost port 8080 端口号 hotOnly false 热更新 overla
  • python四行代码生成“年月日”格式的日期列表序列

    代码如下 import pandas as pd start 20110101 end 20161231 dates pd date range start end strftime Y m d to list 代码运行结果如下 需要说明的
  • 使用Typora将Markdown内容导出为Word(.docx)

    使用Typora将Markdown内容导出为Word docx 操作步骤 01 下载并安装Typora 自行前往Typora官网下载 傻瓜式安装 此处就不再做多余的解释 02 安装Pandoc 2 1 pandoc官网下载 真不知道怎么从这
  • Mongodb 定义model中的某个属性 保存任意类型

    参考 Mongoose5 0 文档http www mongoosejs net docs schematypes html 一个啥都可以放的 SchemaType 虽然便利 但也会让数据难以维护 Mixed 可以通过 Schema Typ
  • Spring @Scheduled @Async联合实现调度任务

    定时任务之前一直用的是quartz之类 但是注意到Spring中其实也提供了一种简单的调度注释 Scheduled 也就想尝一下鲜 代码示意如下 Component EnableScheduling public class AsyncTa