应用场景

有贷款的同学每个月都会收到催还贷款的提醒短信,每天上班、上课前钉钉的打卡提醒,等等。类似这种定时重复的功能,我们就可以使用任务调度来实现。

任务调度框架

调度框架 说明
Timer JDK自带类java.util.Timer,最简单的一种实现任务调度的方法。Timer 的优点在于简单易用,但由于所有任务都是由同一个线程来调度,因此所有任务都是串行执行的,同一时间只能有一个任务在执行,前一个任务的延迟或异常都将会影响到之后的任务。
ScheduledExecutor 鉴于 Timer 的缺陷,Java 5 推出了基于线程池设计的 ScheduledExecutor。其设计思想是,每一个被调度的任务都会由线程池中一个线程去执行,因此任务是并发执行的,相互之间不会受到干扰。需要注意的是,只有当任务的执行时间到来时,ScheduedExecutor 才会真正启动一个线程,其余时间 ScheduledExecutor 都是在轮询任务的状态。
Spring Boot的@Scheduled注解 使用简单,几乎不用编码。满足常见的任务调度需求。很实用。但不适用于分布式集群环境
quartz 应该是目前使用最多的任务调度框架了,功能丰富,支持分布式集群。但不支持任务分片等更高级的功能
ElasticJob ElasticJob是一个分布式调度解决方案,由两个独立的项目组成,ElasticJob- lite和ElasticJob- cloud。ElasticJob-Lite是一个轻量级的,分散的解决方案,提供分布式的任务分片服务;ElasticJob-Cloud利用Mesos来管理和隔离资源。它为每个项目使用统一的作业API。开发人员只需要一次代码,并且可以随意部署。
XXL-JOB 国人开源的分布式任务调度框架,官方中文文档,方便学习。也支持任务分片等。大众点评等一些互联网大厂也在使用。
其它还有LTS等新兴的任务调度框架,个人觉得,使用的时候选择合适的框架就行了,如果你的项目用不了那么多的功能,或者就是个单应用、或者根本不需要分片。因为功能越强大,那么使用起来,实现起来就没有那么容易,这个要看你的项目团队的人员构成和项目的开发成本是否支持你选用更牛逼的架构。否则你的项目很有可能陷入被动调整,或者无法按时交付的风险。

Spring Boot的@Scheduled注解

在单应用下,我们可以使用Spring Boot的@Scheduled注解来实现简单的任务调度。

首先需要使用@EnableScheduling注解开启任务调度

@RestController
@SpringBootApplication(scanBasePackages = "com.yyoo")
// 开启任务调度
@EnableScheduling
public class Appliction {public static void main(String[] args) {SpringApplication.run(Appliction.class, args);}}

使用@Scheduled注解任务执行的方法

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;@Component
public class TaskDemo1 {@Scheduled(cron = "1 * * * * ?")public void doTask1(){// 实际上就是每分钟一次System.out.println("每分钟的第1秒执行一次");}@Scheduled(cron = "1/1 * * * * ?")public void doTask2(){// 分子的1表示从第1秒开始执行,分母表示每隔1秒执行一次。// 但分子我们常常写为*,比如每10秒执行一次*/10// 如果需要每隔5秒执行一次,就是除以5System.out.println("每秒执行一次");}}

cron表达式

任务调度不可避开的要编写cron表达式,各个调度框架、包括linux服务器都有cron表达式来表示任务调度的时间、频率等。(注:各个框架或者linux服务器支持的cron表达式可能会有些许的不同。)
一下按照cron表达式从左至右的顺序

0~59 0~59 0~23 1~31 1~12 1~7 1是周日,7是周六 1970~2099

天和周不能同时表达具体的值,因为1号不一定是周1,所以我们的表达式最后那个周,用?。同理,如果我们要表达具体的周几,那么天这里就只能是?。

年通常我们都不怎么使用,所以我们的示例中只有6位,而没有最后一位年。

cron表达式中的符号

符号 说明
* 表示任意时刻
? 在天或者周上使用
- 表示范围,如:在天上使用1-15,表示1号到15。
/ 表示间隔,指定时间的间隔频率,例如“0-23/2”表示每两小时执行一次。同时正斜线可以和星号一起使用,例如*/10,如果用在minute字段,表示每十分钟执行一次
, 表示枚举,如:在分钟上使用10,30,45,55表示在每个小时的10分钟、30分钟、45分钟、55分钟时执行
L 表示最后的天 或者 周,如在天上使用,L3表示倒数第三天
# 表示第几个星期几,在周上使用,如:7#3 表示第三个周六

@Scheduled的其他用法

//    @Scheduled(fixedDelay = 5000)// 时间默认单位是毫秒,我们可以通过timeUnit属性修改@Scheduled(fixedDelay = 5,timeUnit = TimeUnit.SECONDS)public void doTask3() throws InterruptedException {Thread.sleep(10000);// 休眠10秒来验证(意味着至少要等15秒之后才会再次执行)// 上次调用结束后5秒执行System.out.println("上次调用结束后5秒执行"+Thread.currentThread().getName());}@Scheduled(fixedRate = 5,timeUnit = TimeUnit.SECONDS)public void doTask4() throws InterruptedException {// 每隔5秒执行,无论上次执行是否成功,是否结束System.out.println("每隔5秒执行"+Thread.currentThread().getName());Thread.sleep(10000);}

细心一点的同学运行程序后会发现,我们目前定义了4个任务,貌似执行起来已经不太对劲了。比如每秒执行的任务很久都不执行了。why?

如果我们每个任务方法中都打线程名称后你会发现,打印出的值都是:scheduling-1。说明我们的所有任务都是同一个线程执行的。导致了我们的任务串行化了。此时我们可以通过@Async注解来解决。

配置ThreadPoolTaskScheduler来解决串行化

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;@Configuration
public class ScheduleConfig {@Beanpublic TaskScheduler taskScheduler(){ThreadPoolTaskScheduler tpts = new ThreadPoolTaskScheduler();tpts.setPoolSize(5);// 线程池数量tpts.setThreadNamePrefix("my-Task-");// 线程名称前缀return tpts;}}

@Async异步执行任务调度

与@Scheduled一样,@Async也需要一个注解来开启。在Application类上添加@EnableAsync注解来开启@Async注解支持。最后我们的示例代码如下:

import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;import java.util.concurrent.TimeUnit;@Component
public class TaskDemo1 {@Scheduled(cron = "1 * * * * ?")@Asyncpublic void doTask1(){// 实际上就是每分钟一次System.out.println("每分钟的第1秒执行一次"+Thread.currentThread().getName());}@Scheduled(cron = "1/1 * * * * ?")@Asyncpublic void doTask2(){// 分子的1表示从第1秒开始执行,分母表示每隔1秒执行一次。// 但分子我们常常写为*,比如每10秒执行一次*/10// 如果需要每隔5秒执行一次,就是除以5System.out.println("每秒执行一次"+Thread.currentThread().getName());}//    @Scheduled(fixedDelay = 5000)// 时间默认单位是毫秒,我们可以通过timeUnit属性修改@Scheduled(fixedDelay = 5,timeUnit = TimeUnit.SECONDS)@Asyncpublic void doTask3() throws InterruptedException {Thread.sleep(10000);// 休眠10秒来验证(意味着至少要等15秒之后才会再次执行)// 上次调用结束后5秒执行System.out.println("上次调用结束后5秒执行"+Thread.currentThread().getName());}@Scheduled(fixedRate = 5,timeUnit = TimeUnit.SECONDS)@Asyncpublic void doTask4() throws InterruptedException {// 每隔5秒执行,无论上次执行是否成功,是否结束System.out.println("每隔5秒执行"+Thread.currentThread().getName());Thread.sleep(10000);}}

执行后打印结果正确了,而且线程名字也不一样了。

@Async注释的方法还可以定义异步Future返回

@Async
Future<String> returnSomething(int i) {// this will be run asynchronously
}

使用@Async来异步调用之后,我们之前配置的ThreadPoolTaskScheduler就没有效果了。因为你会看到有第6、第7甚至第8个线程出现。使用@Async来处理异步任务调度,spring自动控制线程的数量,如果需要自己控制,就自定义配置ThreadPoolTaskScheduler把。

上一篇:Spring Boot logback日志
下一篇:待续

Spring Boot 任务调度相关推荐

  1. 纸上得来终觉浅,绝知此事要躬行——Spring boot任务调度

    前言:之前今日开讲项目的时候,用到了Quartz进行任务调度.后来做一个电商项目的时候,还用到了Quartz任务调度. 觉得挺简单的,a peace of cake.  忽略了总结,当时闭着眼睛都能捉 ...

  2. 【Linux部署】Spring Boot 项目部署在Linux环境下的Docker容器内举例【任务调度系统 xxl-job 任务调度中心】(手动版)

    1.将SpringBoot项目打jar包 这里打包的是xxl-job任务调度系统的调度器. 2.编写Dockerfile FROM java:8 VOLUME /tmp ADD xxl-job-adm ...

  3. 源码分享-基于Spring Boot为美柚大数据研发的大数据任务调度平台

    此项目为美柚大数据研发的大数据任务调度平台,提供Spark.Flink等离线任务的调度以及实时任务的监控,并具有批次积压报警.任务异常重启.重复应用监测.大内存应用监测等功能. Big Whale - ...

  4. Spring Boot + Security + MyBatis + Thymeleaf + Activiti 快速开发平台项目

    项目介绍 Spring Boot + Security + MyBatis + Thymeleaf + Activiti 快速开发平台 基于 Layui 的后台管理系统模板,扩展 Layui 原生 U ...

  5. Spring Boot 整合 Quartz 实现 Java 定时任务的动态配置

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 首先说下这次主题,动态配置.没接触过定时任务的同学可以先看 ...

  6. Spring Boot + MyBatis + Druid + PageHelper 实现多数据源并分页

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 作者 | 虚无境 链接 | cnblogs.com/xuwujin ...

  7. 分享13个Spring Boot 优质开源项目!商城,ERP,管理系统

    Spring Boot 算是目前 Java 领域最火的技术栈了,也是Java开发人员不得不掌握的技术,今天给大家整理了13个优质 Spring Boot 开源项目给大家参考,希望能够帮助到正在学习 S ...

  8. 基于Spring Boot+Cloud构建微云架构

    链接:my.oschina.net/u/3636867/blog/1802517 前言 首先,最想说的是,当你要学习一套最新的技术时,官网的英文文档是学习的最佳渠道.因为网上流传的多数资料是官网翻译而 ...

  9. Spring Boot定时任务应用实践

    在Spring Boot中实现定时任务功能,可以通过Spring自带的定时任务调度,也可以通过集成经典开源组件Quartz实现任务调度. 一.Spring定时器 1.cron表达式方式 使用自带的定时 ...

最新文章

  1. 大型软件公司.net面试题!一定得看(附答案)
  2. 多种方法解决Exchange 2010 EMC批量启用邮箱之后出..
  3. JavaFX 2:如何加载图像
  4. Android开源源码推荐(一)
  5. 【三维深度学习】Sparse Convolutional Network 基于稀疏采样不变性的深度稠密重建
  6. r语言ggplot画两条曲线_R语言作图——Line plot with error
  7. 由一个网站注册验证码带来的思考
  8. ibatis 核心原理解析
  9. H.264 NAL层解析
  10. 《Python 黑帽子》学习笔记 - 原书 netcat 代码分析 - Day 7
  11. Java Web开发后端常用技术汇总
  12. 如何训练大脑提升专注力
  13. 【Mac实用技巧】Mac如何修复YouTube视频黑屏现象?
  14. 轻量级 android模拟器,【分享中控】轻量级中控系统
  15. 白光led 计算机模拟,高显色指数LED白光的色度学模拟方法研究
  16. Ubuntu20.04安装中国版firefox
  17. QIIME 2:可重复、交互和扩展的微生物组数据分析流程
  18. 1、模拟蚂蚁借呗—利息计算
  19. 写能执行cmd命令的bat文件
  20. 【游戏编程扯淡精粹】如何学习编程语言

热门文章

  1. 密码对的还出现 Access denied for user ‘‘@‘localhost‘ (using password: NO) 错误
  2. 极海推出APM32A系列车规级MCU
  3. BUUCTF:zip
  4. SMC SY系列电磁换向阀
  5. Python编程:从入门到实践——列表简介(第三章+课后答案)
  6. mac 13.0 自动关机设置
  7. Pandas 中 SettingwithCopyWarning 的原理和解决方案
  8. 使用正则批量修改文件名
  9. 五组数据告诉你倒闭企业的“死亡画像”
  10. 志翔科技用大数据技术为行业云构建“安全之翼”