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

【开发篇】十五、Spring Task实现定时任务

文章目录

  • 1、使用示例
  • 2、相关配置
  • 3、@Scheduled注解
  • 4、Spring Task单线程下的阻塞坑
  • 5、Spring Task阻塞问题的处理思路
  • 6、Spring Task在分布式环境中

上一篇用Quartz来实现了定时任务,但相对来说,这个框架还是比较繁琐。Spring Boot默认在无任何第三方依赖的情况下使用Spring-context模块下提供的定时任务工具 Spring Task

1、使用示例

@EnableScheduling开启定时任务功能:

@SpringBootApplication@EnableSchedulingpublic class TaskApplication {   public static void main(String[] args) {  SpringApplication.run(TaskApplication.class, args); }
}

接下来就可以通过@Scheduled注解方式自定义定时任务:

@Component
public class ScheduledBean {    @Scheduled(cron = "0/5 * * * * ?")    public void printLog(){  System.out.println(Thread.currentThread().getName()+":run...");  }
}

重启服务:

在这里插入图片描述

2、相关配置

以上是基本使用,还可配置一些通用配置,如下:

spring:  task:    scheduling:      # 任务调度线程池大小,因为要开线程异步,最多能开几个线程?,默认 1     pool:       size: 1      # 调度线程名称前缀 默认 scheduling-,程序线程一多,不好找,加了它可读性高     thread-name-prefix: ssm_     shutdown:        # 线程池关闭时,是否等待所有任务完成        await-termination: false        # 调度线程关闭前最大等待时间,确保最后一定关闭(如果等待,最多等几秒)        await-termination-period: 10s

注意thread-name-prefix配置,是日志里定时任务的线程的前缀,默认为scheduling-num,num即序号。以上这个配置由TaskSchedulingProperties类从yaml中接收。

在这里插入图片描述

3、@Scheduled注解

整理下@Scheduled注解的常用属性:

  • cron,cron表达式,语法跳这篇【cron表达式语法】
  • fixedDelay,固定时延。从上次任务执行结束的时间开始,到下个任务开始的时间间隔。不关心任务逻辑、任务本身执行多长时间。下图为fixedDelay为4s时的示意图:

在这里插入图片描述

  • fixedRate,固定频率。在理想情况下,下一次开始和上一次开始之间的时间间隔是一定的,但当如果上一次任务因为其他原因超时好久,而pool.size的默认值为1,即默认情况下 Spring Boot 定时任务是单线程执行的,那下一轮任务就会被阻塞。类比地铁每隔10分钟发一列,也就是说所有列车其实已经安排好了时刻表,理想情况下,每列车准点发就行了,互不影响,但是如果其中一列晚点,那么就会导致下一列晚点。

图片来源cloud.tencent.com/developer/article/1582434

  • initialDelay:初始化延迟时间,也就是第一次延迟执行的时间。这个参数对 cron 属性无效,只能配合 fixedDelay 或 fixedRate 使用。如 @Scheduled(initialDelay=5000,fixedDelay = 1000) 表示第一次延迟 5000 毫秒执行,下一次任务在上一次任务结束后 1000 毫秒后执行。

fixedDelay和fixedRate,都是和两轮任务有关,但前者关注的是第一轮的结束时间和第二轮的开始时间的这个间隔。而后者关注的都是两轮的开始时间中间的这个间隔。

4、Spring Task单线程下的阻塞坑

demo代码,演示两个任务在单线程下的阻塞:

@Component
public class ScheduleTask {/*** 上一次任务执行完后,歇一秒,再执行下一轮* 执行一次任务耗时5秒*/@Scheduled(fixedDelay = 1000)public void task1() throws InterruptedException {System.out.println(Thread.currentThread().getName()+ "==>  spring task 1 ==> "+ LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss:SSS")));Thread.sleep(5000);}/*** 下轮任务在上一轮任务开始后2秒执行.* 执行一次任务耗时可忽略*/@Scheduled(fixedRate = 2000)public void task2() {System.out.println(Thread.currentThread().getName()+ "==>  spring task2 ==> "+ LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss:SSS")));}}

执行效果:

在这里插入图片描述

可以看到task2被连续执行三次,且不妙的是两次任务开始时间没有间隔2s。这就是单线程下阻塞导致的问题,task1执行的5秒内,task2按预定的间隔触发的任务被阻塞,等task1一执行完,就会立刻执行这些阻塞的任务。这个延迟和堆积在生产中还是很严重的。

5、Spring Task阻塞问题的处理思路

第一种是直接改配置文件:

既然问题在单线程,一个线程处理不过来而导致的问题,那让定时任务的执行改为多线程就行了:

pring:  task:    scheduling:      # 任务调度线程池大小,因为要开线程异步,最多能开几个线程?,默认 1     pool:       size: 1     # 像上面的demo,设size为2即可 

第二种是定义配置类,实现SchedulingConfigurer接口,设置taskScheduler:

@Configuration
public class ScheduleConfig implements SchedulingConfigurer {@Overridepublic void configureTasks(ScheduledTaskRegistrar taskRegistrar) {//设定一个长度10的定时任务线程池,这个大小自己判断taskRegistrar.setScheduler(Executors.newScheduledThreadPool(10));}
}
以下是这种的方式之所以能实现的源码解析:

可以从@EnableScheduling注解源码开始分析得出,先看这个注解导入的SchedulingConfiguration类:

在这里插入图片描述

返回一个调度注解Bean的后置处理器:

在这里插入图片描述

往下跟这个后置处理器的构造方法,看到了ScheduledTaskRegistrar,

在这里插入图片描述

往下跟也就看到了为什么Spring Task默认是单线程的,这里new的是一个单线程的调度执行器:

在这里插入图片描述

而上面自己写配置类,setScheduler即可跳过上面的默认单线程配置。

第三种是加@Async注解开启异步任务

启动类加@EnableAsyn开启注解支持c,在定时任务方法上加入注解@Async

@Async
@Schedule(...)
public void task1(){//...
}@Async
@Schedule(...)
public void task2(){//...
}

如果有@Async这个注解的额外配置需求,参考:

//非必须,看自己需求
@Bean
public ThreadPoolTaskExecutor taskExecutor() {ThreadPoolTaskExecutor poolTaskExecutor = new ThreadPoolTaskExecutor();poolTaskExecutor.setCorePoolSize(4);poolTaskExecutor.setMaxPoolSize(6);// 设置线程活跃时间(秒)poolTaskExecutor.setKeepAliveSeconds(120);// 设置队列容量poolTaskExecutor.setQueueCapacity(40);poolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());// 等待所有任务结束后再关闭线程池poolTaskExecutor.setWaitForTasksToCompleteOnShutdown(true);return poolTaskExecutor;
}

6、Spring Task在分布式环境中

在这里插入图片描述

相关文章:

【开发篇】十五、Spring Task实现定时任务

文章目录 1、使用示例2、相关配置3、Scheduled注解4、Spring Task单线程下的阻塞坑5、Spring Task阻塞问题的处理思路6、Spring Task在分布式环境中 上一篇用Quartz来实现了定时任务,但相对来说,这个框架还是比较繁琐。Spring Boot默认在无任何第三方依赖…...

Python常用功能的标准代码

后台运行并保存log 1 2 3 4 5 6 7 8 9 nohup python -u test.py > test.log 2>&1 & #最后的&表示后台运行 #2 输出错误信息到提示符窗口 #1 表示输出信息到提示符窗口, 1前面的&注意添加, 否则还会创建一个名为1的文件 #最后会把日志文件输出到test.log文…...

Electron.js入门-构建第一个聊天应用程序

什么是electron 电子是一个开源框架,用于使用web技术构建跨平台桌面应用程序;即: HTML、CSS和JavaScript;被集成为节点模块,我们可以为我们的应用程序使用节点的所有功能;组件,如数据库、Api休…...

ubuntu 22.04 更新NVIDIA显卡驱动,重启后无网络图标等系统奇奇怪怪问题

环境 win10, ubuntu 22.04双系统 笔记本电脑,4060显卡 解决思路 具体的过程当时没有记录下来,然后因为在解决系统的问题,也没有截图啥的,只有一些大概记忆,供未来的自己参考吧。 首先是更新显卡驱动 我是直接在soft…...

Python综合案例:学生管理系统

目录 需求说明: 功能: 创建入口函数: 实现菜单函数: 实现增删查操作: 1. 新增学生 2. 展示学生 3. 查找学生 4. 删除学生 加入存档读档: 1. 约定存档格式 2. 实现存档函数 3. 实现读档函数 打…...

IDT 一款自动化挖掘未授权访问漏洞的信息收集工具

IDT v1.0 IDT 意为 Interface detection(接口探测) 项目地址: https://github.com/cikeroot/IDT/该工具主要的功能是对批量url或者接口进行存活探测,支持浏览器自动打开指定的url,避免手动重复打开网址。只需输入存在批量的url文件即可。 …...

复习 --- 消息队列

进程间通信机制(IPC) 简述 IPC:Inter Process Communication 进程和进程之间的用户空间相互独立,但是4G内核空间共享,进程间的通信就是通过这4G的内核空间 分类 传统的进程间通信机制 无名管道(pipe) 有名管道&…...

AcWing 288. 休息时间,《算法竞赛进阶指南》

288. 休息时间 - AcWing题库 在某个星球上,一天由 N 个小时构成,我们称 0 点到 1 点为第 1 个小时、1 点到 2 点为第 2 个小时,以此类推。 在第 i 个小时睡觉能够恢复 Ui 点体力。 在这个星球上住着一头牛,它每天要休息 B 个小…...

ES6中字符串的扩展

字符串的遍历器接口 使用for…of for(let x of foo) {console.log(x); } // f; o; oat() ES5中的charAt()方法,返回字符串给定位置的字符。但是不能识别码点大于0xFFFF的字符,at方法可以 includes()、startsWith()、endsWith() 用来确定一个字符串是…...

GEO生信数据挖掘(四)数据清洗(离群值处理、低表达基因、归一化、log2处理)

检索到目标数据集后,开始数据挖掘,本文以阿尔兹海默症数据集GSE1297为例 目录 离群值处理 删除 低表达基因 函数归一化,矫正差异 数据标准化—log2处理 完整代码 上节围绕着探针ID和基因名称做了一些清洗工作,还做了重复值检查…...

CI/CD工具中的CI和CD的含义

CI/CD工具中的CI和CD的含义? CI/CD 是现代软件开发方法中广泛使用的一种方法。其中,CI 代表持续集成(Continuous Integration),CD 则有两层含义,一是持续交付(Continuous Delivery)…...

用go获取IPv4地址,WLAN的IPv4地址,本机公网IP地址详解

文章目录 获取IPv4地址获取WLAN的IPv4地址获取本机公网IP地址 获取IPv4地址 下面的代码会打印出本机所有的IPv4地址。这个方法可能会返回多个IP地址,因为一台机器可能有多个网络接口,每个接口可能有一个或多个IP地址。 package mainimport ("fmt&…...

Android自定义Drawable---灵活多变的矩形背景

Android自定义Drawable—灵活多变的矩形背景 在安卓开发中,我们通常需要为不同的按钮设置不同的背景以实现不同的效果,有时还需要这些按钮根据实际情况进行变化。如果采用编写resource中xml文件的形式,就需要重复定义许多只有微小变动的资源…...

ParagonNTFSforMac_15.5.102中文版最受欢迎的NTFS硬盘格式读取工具

Paragon NTFS for Mac是一款可以为您轻松解决Mac平台上不能识别Windows通用的NTFS文件难题,这是一款强大的Mac读写工具,相信在很多时候,Mac用户需要对NTFS文件的移动硬盘进行写入,但是macOS系统默认是不让写入的,使用小…...

Kafka 搭建过程

目录 1.关于Kafka2.Kafka 搭建过程3.参考 本文主要介绍Kafka基本原理,以及搭建过程。 1.关于Kafka Apache Kafka是一个开源的分布式事件流平台,被设计用来实现实时数据流的发布、订阅、存储和处理。 Kafka的主要特性包括: 高吞吐量&#x…...

七、2023.10.1.Linux(一).7

文章目录 1、 Linux中查看进程运行状态的指令、查看内存使用情况的指令、tar解压文件的参数。2、文件权限怎么修改?3、说说常用的Linux命令?4、说说如何以root权限运行某个程序?5、 说说软链接和硬链接的区别?6、说说静态库和动态…...

一文教你搞懂Redis集群

一、Redis主从 1.1、搭建主从架构 单节点的Redis的并发能力是有上限的,要进一步的提高Redis的并发能力,据需要大家主从集群,实现读写分离。 共包含三个实例,由于资源有限,所以在一台虚拟机上,开启多个red…...

树上启发式合并 待补

对于每个子树&#xff0c;直接遍历所有轻儿子&#xff0c;继承重儿子 会了板子后&#xff0c;修改维护的东西和莫队是一样的 洛谷 U41492 #include <bits/stdc.h> #define ll long long #define ull unsigned long long constexpr int N1e55; std::vector<int> e…...

minio分布式文件存储

基本介绍 什么是 MinIO MinIO 是一款基于 Go 语言的高性能、可扩展、云原生支持、操作简单、开源的分布式对象存储产品。基于 Apache License v2.0 开源协议&#xff0c;虽然轻量&#xff0c;却拥有着不错的性能。它兼容亚马逊S3云存储服务接口。可以很简单的和其他应…...

Linux新的IO模型io_uring

一、Linux下的网络通信模型 在网络开发的过程中&#xff0c;需要处理好几个问题。首先是通信的内核支持问题&#xff1b;其次是通信的模型问题&#xff1b;最后是框架问题。这些问题在闭源的OS如Windows上&#xff0c;基本上不算什么大问题&#xff08;因为只能用人家的API&am…...

[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解

突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 ​安全措施依赖问题​ GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...

脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)

一、数据处理与分析实战 &#xff08;一&#xff09;实时滤波与参数调整 基础滤波操作 60Hz 工频滤波&#xff1a;勾选界面右侧 “60Hz” 复选框&#xff0c;可有效抑制电网干扰&#xff08;适用于北美地区&#xff0c;欧洲用户可调整为 50Hz&#xff09;。 平滑处理&…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练

前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1)&#xff1a;从基础到实战的深度解析-CSDN博客&#xff0c;但实际面试中&#xff0c;企业更关注候选人对复杂场景的应对能力&#xff08;如多设备并发扫描、低功耗与高发现率的平衡&#xff09;和前沿技术的…...

dedecms 织梦自定义表单留言增加ajax验证码功能

增加ajax功能模块&#xff0c;用户不点击提交按钮&#xff0c;只要输入框失去焦点&#xff0c;就会提前提示验证码是否正确。 一&#xff0c;模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...

NLP学习路线图(二十三):长短期记忆网络(LSTM)

在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中&#xff0c;新增了一个本地验证码接口 /code&#xff0c;使用函数式路由&#xff08;RouterFunction&#xff09;和 Hutool 的 Circle…...

JS设计模式(4):观察者模式

JS设计模式(4):观察者模式 一、引入 在开发中&#xff0c;我们经常会遇到这样的场景&#xff1a;一个对象的状态变化需要自动通知其他对象&#xff0c;比如&#xff1a; 电商平台中&#xff0c;商品库存变化时需要通知所有订阅该商品的用户&#xff1b;新闻网站中&#xff0…...

GraphQL 实战篇:Apollo Client 配置与缓存

GraphQL 实战篇&#xff1a;Apollo Client 配置与缓存 上一篇&#xff1a;GraphQL 入门篇&#xff1a;基础查询语法 依旧和上一篇的笔记一样&#xff0c;主实操&#xff0c;没啥过多的细节讲解&#xff0c;代码具体在&#xff1a; https://github.com/GoldenaArcher/graphql…...

DiscuzX3.5发帖json api

参考文章&#xff1a;PHP实现独立Discuz站外发帖(直连操作数据库)_discuz 发帖api-CSDN博客 简单改造了一下&#xff0c;适配我自己的需求 有一个站点存在多个采集站&#xff0c;我想通过主站拿标题&#xff0c;采集站拿内容 使用到的sql如下 CREATE TABLE pre_forum_post_…...

面试高频问题

文章目录 &#x1f680; 消息队列核心技术揭秘&#xff1a;从入门到秒杀面试官1️⃣ Kafka为何能"吞云吐雾"&#xff1f;性能背后的秘密1.1 顺序写入与零拷贝&#xff1a;性能的双引擎1.2 分区并行&#xff1a;数据的"八车道高速公路"1.3 页缓存与批量处理…...