Spring定时任务高级使用篇

前面一篇博文 《Spring之定时任务基本使用篇》 介绍了Spring环境下,定时任务的简单使用姿势,也留了一些问题,这一篇则希望能针对这些问题给个答案

I. 定时任务进阶篇

1. 问题小结

前面一篇博文,抛出了下面的几个问题,接下来则围绕问题进行分析

  • 一个项目中有多个定时任务时,他们是并行执行的还是串行执行的?
  • 如果默认是串行的
    • 那么有相同的crond表达式的定时任务之间,有先后顺序么?
    • 某个任务的阻塞是否会影响后面的任务?
    • 如果需要他们并行执行,可以怎么做?
  • 如果是并发执行的
    • 是新创建线程还是采用线程池来复用呢?
    • 在并发执行时,假设有个每秒执行一次的任务,但是它执行一次消耗的时间大于1s时,这个任务的表现时怎样的呢?不断地新增线程来执行还是等执行完毕之后再执行下一次的呢?

2. 多定时任务的串并行分析

如何确认一个项目中的多个定时任务是串行执行还是并发执行呢?要想验证这个功能,最好的法子就是写个testcase,比如定义两个定时任务,在其中一个任务中写个死循环,看另外一个任务是否会正常执行

@Scheduled(cron = "0/1 * * * * ?")
public void sc1() throws InterruptedException {
System.out.println(Thread.currentThread().getName() + " | sc1 " + System.currentTimeMillis());
while (true) {
Thread.sleep(5000);
}
} @Scheduled(cron = "0/1 * * * * ?")
public void sc2() {
System.out.println(Thread.currentThread().getName() + " | sc2 " + System.currentTimeMillis());
}

首先我们分析的是 sc1和sc2这两个任务的执行是串行还是并行的,暂时先不考虑 sc1 调用时阻塞,下一秒是否是开新的线程再调用sc1

  • 若串行:则sc1打印一次,sc2可能打印0或者1次
  • 若并行:sc1打印一次,sc2打印n多次

实际运行,GIF图演示如下

上图的结果,印证了默认的情况下,多个定时任务时串行执行的;如果一个任务出现阻塞,其他的任务都会受到影响

3. 定时任务执行的优先级

既然是顺序执行的,那么优先级怎么定?每次都是固定的,还是随机的呢?

要验证上面的方法,也容易,同样两个任务,看他们的输出是否会乱掉,如果每次都是任务1打印完再打印任务2,那就是固定优先级的;否则每次调度时,顺序不好说

测试代码如下

@Scheduled(cron = "0/1 * * * * ?")
public void sc1() {
System.out.println(Thread.currentThread().getName() + " | sc1 " + System.currentTimeMillis());
} @Scheduled(cron = "0/1 * * * * ?")
public void sc2() {
System.out.println(Thread.currentThread().getName() + " | sc2 " + System.currentTimeMillis());
}

实测结果如下

从输出得出结论:顺序是串掉的,并没有表现出明显的优先级关系

4. 并行调度

接下来的问题就是我希望这些任务可以并发执行,可以实现么?

当然是可以,用起来也比较简单,首先是在Application上添加注解@EnableAsync,开启异步调用,然后再计划任务上加上@Async注解即可,一个简单的demo如下

@EnableAsync
@EnableScheduling
@SpringBootApplication
public class QuickMediaApplication { public static void main(String[] args) {
SpringApplication.run(QuickMediaApplication.class, args);
} @Scheduled(cron = "0/1 * * * * ?")
@Async
public void sc1() {
System.out.println(Thread.currentThread().getName() + " | sc1 " + System.currentTimeMillis());
}
}

上面执行之后,查看输出(异步调度时,理论上线程名应该不一样)

从上面的输出,可以简单的推理,每次调度上面的任务都是新开了一个线程来做的,所以如果在定时任务中写了死循环,是否会导致无限线程,最后整个进程崩掉?

额外提一句,linux系统下单进程的线程数是有上线的,查看命令为:

ulimit -u

在测试之前,先看下上面的正常任务执行,如下面的动图,线程数并没有夸张的长法

接下来换成死循环的调度方式,实际测试如下,线程数蹭蹭的上涨

所以使用默认的异步调用方式,并不是一个好注意,说不准就被玩死了自己都不知道,那么可以用自己的线程池来管理这些异步任务么?

5. 自定义线程池

用自定义的线程池来取代默认线程管理方式,无疑是一个更加安全和灵活的方式,使用起来也并不麻烦,和平常创建线程池的套路没什么区别,要在Spring生态中使用,就把它搞成bean即可

直接借助Spring的线程池ThreadPoolTaskExecutor

@Bean
public AsyncTaskExecutor asyncTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setThreadNamePrefix("yhh-schedule-");
executor.setMaxPoolSize(10);
executor.setCorePoolSize(3);
executor.setQueueCapacity(0);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
return executor;
} @Scheduled(cron = "0/1 * * * * ?")
@Async
public void sc1() throws InterruptedException {
System.out.println(Thread.currentThread().getName() + " | sc1 " + System.currentTimeMillis());
while (true) {
Thread.sleep(1000 * 5);
}
}

实际演示的结果如下,最多10个线程,再提交的任务直接丢弃

简单说一下,用自定义线程池的好处:

  • 合理的分配线程池参数
  • 拒绝策略的选择也比较有意思(可以按照自己的想法来处理"负载"的任务)
  • 线程池命名,对于以后问题排查,会有很大的帮助

6. 小结

本来这篇博文在昨天即8月2号就应该写完的,结果晚上生产环境下除了点问题,解决线上故障之后就比较晚了,留到了今天,哎,拖延症也是要不得。。。

下面小结Spring中定时任务的几个知识点

  • 默认所有的定时任务都是串行调度的,一个线程,且即便crond完全相同的两个任务先后顺序也没法保证(具体原因需要源码分析,看下这块是怎么支持)
  • 使用@Async注解可以使定时任务异步调度;但是需要开启配置,在启动类上添加 @EnableAsync 注解
  • 开启并发执行时,推荐用自定义的线程池来替代默认的,理由见上面

II. 其他

0. 相关

1. 一灰灰Bloghttps://liuyueyi.github.io/hexblog

一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛

2. 声明

尽信书则不如,已上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激

3. 扫描关注

小灰灰Blog&公众号

知识星球

180803-Spring定时任务高级使用篇的更多相关文章

  1. spring 定时任务配置

    1.(易)如何在spring中配置定时任务? spring的定时任务配置分为三个步骤: 1.定义任务 2.任务执行策略配置 3.启动任务 (程序中一般我们都是到过写的,直观些) 1.定义任务 < ...

  2. 关于Spring定时任务(定时器)用法

    Spring定时任务的几种实现 Spring定时任务的几种实现 一.分类 从实现的技术上来分类,目前主要有三种技术(或者说有三种产品): 从作业类的继承方式来讲,可以分为两类: 从任务调度的触发时机来 ...

  3. (3)Spring定时任务的几种实现

    Spring定时任务的几种实现 近日项目开发中需要执行一些定时任务,比如需要在每天凌晨时候,分析一次前一天的日志信息,借此机会整理了一下定时任务的几种实现方式,由于项目采用spring框架,所以我都将 ...

  4. spring定时任务的几种实现方式

    Spring定时任务的几种实现 近日项目开发中需要执行一些定时任务,比如需要在每天凌晨时候,分析一次前一天的日志信息,借此机会整理了一下定时任务的几种实现方式,由于项目采用spring框架,所以我都将 ...

  5. (转)Spring定时任务的几种实现

    Spring定时任务的几种实现 博客分类: spring框架 quartzspringspring-task定时任务注解  Spring定时任务的几种实现 近日项目开发中需要执行一些定时任务,比如需要 ...

  6. Spring AOP高级——源码实现(3)AopProxy代理对象之JDK动态代理的创建过程

    spring-aop-4.3.7.RELEASE  在<Spring AOP高级——源码实现(1)动态代理技术>中介绍了两种动态代理技术,当然在Spring AOP中代理对象的生成也是运用 ...

  7. 解决spring定时任务执行2次和tomcat部署缓慢的问题

    spring定时任务执行2次 问题重现和解析 最近使用quartz定时任务框架,结果发现开发环境执行无任何问题,部署到服务器上后,发现同一时间任务执行了多次.经过搜索发现是服务器上tomcat的配置文 ...

  8. 180801-Spring之定时任务基本使用篇

    文章链接:https://liuyueyi.github.io/hexblog/2018/08/01/180801-Spring之定时任务基本使用篇/ Spring之定时任务基本使用篇 spring- ...

  9. Spring Boot高级

    Spring Boot高级内容概要一.Spring Boot与缓存二.Spring Boot与消息三.Spring Boot与检索四.Spring Boot与任务五.Spring Boot与安全六.S ...

随机推荐

  1. impdp导入expdp导出数据库实例

    impdp命令在cmd下直接用,不必登录oracle.只能导入expdp导出的dmp文件. expdp导出的时候,需要创建 DIRECTORY 导出什么表空间,导入也要什么表空间. 导出什么用户,导入 ...

  2. BZOJ1029:[JSOI2007]建筑抢修(贪心,堆)

    Description 小刚在玩JSOI提供的一个称之为“建筑抢修”的电脑游戏:经过了一场激烈的战斗,T部落消灭了所有z部落的 入侵者.但是T部落的基地里已经有N个建筑设施受到了严重的损伤,如果不尽快 ...

  3. 3631. [JLOI2014]松鼠的新家【树形DP】

    Description 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他居然真的住在“树”上.松鼠想邀 ...

  4. 【bzoj4543】[POI2014]Hotel加强版

    题目 抄题解.jpg 发现原来的\(O(n^2)\)的换根\(dp\)好像行不通了呀 我们考虑非常牛逼的长链剖分 我们设\(f[x][j]\)表示在\(x\)的子树中距离\(x\)为\(j\)的点有多 ...

  5. ethers.js-1

    https://docs.ethers.io/ethers.js/html/ What is ethers.js The ethers.js library aims to be a complete ...

  6. 详解Tensorflow数据读取有三种方式(next_batch)

    转自:https://blog.csdn.net/lujiandong1/article/details/53376802 Tensorflow数据读取有三种方式: Preloaded data: 预 ...

  7. OpenCV——RGB和HSV颜色空间

    RGB颜色空间 在RGB中,一幅图像有三个独立的图像平面或通道组成:红,绿,蓝(以及第四个通道透明度). RGB颜色表 资料:网络  ◇  编制:王践舜 RGB(255,23,140)是光的三原色,也 ...

  8. PAT02-线性结构3 Reversing Linked List

    题目:https://pintia.cn/problem-sets/1010070491934568448/problems/1037889290772254722 先是看了牛客(https://ww ...

  9. Pat乙级1011题:A+B和C

    题目:给定区间[-2的31次方, 2的31次方]内的3个整数A.B和C,请判断A+B是否大于C. 我写的代码: del abc(self,a,b,c,i): if a+b>c: print(&q ...

  10. JDK(八)JDK1.7&1.8源码对比分析【集合】HashMap

    前言 在JDK1.8源码分析[集合]HashMap文章中,我们分析了HashMap在JDK1.8中新增的特性(引进了红黑树数据结构),但是为什么要进行这个优化呢?这篇文章我们通过对比JDK1.7和1. ...