您当前的位置:首页 > 电脑百科 > 程序开发 > 框架

SpringBoot中的定时任务的同步与异步你确定真的知道?

时间:2021-02-24 16:19:12  来源:  作者:

定时任务调度功能在我们的开发中是非常常见的,随便举几个例子:定时清除一些过期的数据,定时发送邮件等等,实现定时任务调度的方式也十分多样,本篇文章主要学习各种实现定时任务调度方式的优缺点,以便为日后选择的时候提供一定的参考。

本篇要点

  • 介绍Timer实现定时任务。
  • 介绍ScheduledExecutorService实现定时任务。
  • 介绍SpringBoot使用SpringTask实现定时任务。
  • 介绍SpringBoot使用SpringTask实现异步任务。

Timer实现定时任务

基于JDK自带的JAVA.util.Timer,通过调度java.util.TimeTask让某一段程序按某一固定间隔,在某一延时之后定时执行。

缺点:

  1. 无法指定某一时间的时候执行。
  2. 存在潜在bug,Timer运行多个TimeTask时,只要其中之一没有捕获抛出的异常,其它任务便会自动终止运行。
public class DemoTimer {

    //延时时间
    private static final long DELAY = 3000;

    //间隔时间
    private static final long PERIOD = 5000;

    public static void main(String[] args) {
        // 定义要执行的任务
        TimerTask task = new TimerTask() {
            @Override
            public void run() {
                System.out.println("任务执行 --> " + LocalDateTime.now());
            }
        };
        Timer timer = new Timer();
        timer.schedule(task, DELAY, PERIOD);
    }
}

ScheduledExecutorService实现定时任务

阿里巴巴开发规范明确规定:希望开发者使用ScheduledExecutorService代替Timer。

多线程并行处理定时任务时,Timer运行多个TimeTask时,只要其中之一没有捕获抛出的异常,其它任务便会自动终止运行,使用ScheduledExecutorService则没有这个问题。

public class DemoScheduledExecutorService {

    //延时时间
    private static final long DELAY = 3000;

    //间隔时间
    private static final long PERIOD = 5000;

    public static void main(String[] args) {

        Runnable task = new Runnable() {
            @Override
            public void run() {
                System.out.println("任务执行 --> " + LocalDateTime.now());
            }
        };

        ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
        service.scheduleAtFixedRate(task, DELAY, PERIOD, TimeUnit.MILLISECONDS);

    }
}

SpringBoot使用Spring Task实现定时任务

自动配置实现原理

Spring为我们提供了异步执行任务调度的方式,提供TaskExecutor,TaskScheduler接口,而SpringBoot的自动配置类org.springframework.boot.autoconfigure.task.TaskSchedulingAutoConfiguration为我们默认注入了他们的实现:ThreadPoolTaskScheduler,本质上是ScheduledExecutorService 的封装,增强在调度时间上的功能。

SpringBoot中的定时任务的同步与异步你确定真的知道?

 

@ConditionalOnClass(ThreadPoolTaskScheduler.class)
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(TaskSchedulingProperties.class)
@AutoConfigureAfter(TaskExecutionAutoConfiguration.class)
public class TaskSchedulingAutoConfiguration {

	@Bean
	@ConditionalOnBean(name = TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)
	@ConditionalOnMissingBean({ SchedulingConfigurer.class, TaskScheduler.class, ScheduledExecutorService.class })
	public ThreadPoolTaskScheduler taskScheduler(TaskSchedulerBuilder builder) {
		return builder.build();
	}

	@Bean
	@ConditionalOnMissingBean
	public TaskSchedulerBuilder taskSchedulerBuilder(TaskSchedulingProperties properties,
			ObjectProvider<TaskSchedulerCustomizer> taskSchedulerCustomizers) {
		TaskSchedulerBuilder builder = new TaskSchedulerBuilder();
		builder = builder.poolSize(properties.getPool().getSize());
		Shutdown shutdown = properties.getShutdown();
		builder = builder.awaitTermination(shutdown.isAwaitTermination());
		builder = builder.awaitTerminationPeriod(shutdown.getAwaitTerminationPeriod());
		builder = builder.threadNamePrefix(properties.getThreadNamePrefix());
		builder = builder.customizers(taskSchedulerCustomizers);
		return builder;
	}

}

新建工程,引入依赖

Spring Task是Spring Framework中的模块,我们只需引入spring-boot-starter依赖就可以了。

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

编写配置类@EnableScheduling

@Configuration
@EnableScheduling
public class ScheduleConfig {

}
  • @Configuration表明这是个配置类。
  • @EnableScheduling表明启用Spring的定时任务调度功能。

定义定时任务@Scheduled

@Component
@Slf4j
public class DemoTask {

    private final AtomicInteger counts = new AtomicInteger();

    @Scheduled(cron = "0/5 * * * * *")
    public void execute() {
        log.info("[定时任务第 {} 次执行]", counts.incrementAndGet());
    }
}
  • @Component表明该类需要被扫描,以便于Spring容器管理。
  • @Scheduled标注需要调度执行的方法,定义执行规则,其必须指定cron、fixedDelay或fixedRate三个属性其中一个。cron:定义Spring cron表达式,网上有在线cron生成器,可以对照着编写符合需求的定时任务。fixedDelay :固定执行间隔,单位:毫秒。注意,以调用完成时刻为开始计时时间。fixedRate :固定执行间隔,单位:毫秒。注意,以调用开始时刻为开始计时时间。

主启动类

@SpringBootApplication
public class SpringBootTaskApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringBootTaskApplication.class, args);
    }
}

定义配置文件

Spring Task 调度任务的配置,对应 TaskSchedulingProperties 配置类。SpringBoot允许我们在yml或properties定制这些外部化配置,如果不配置也是没有关系的,自动配置已经给你一套默认的值了。

spring:
  task:
    scheduling:
      thread-name-prefix: summerday- # 线程池的线程名的前缀。默认为 scheduling- ,建议根据自己应用来设置
      pool:
        size: 10 # 线程池大小。默认为 1 ,根据自己应用来设置
      shutdown:
        await-termination: true # 应用关闭时,是否等待定时任务执行完成。默认为 false ,建议设置为 true
        await-termination-period: 60 # 等待任务完成的最大时长,单位为秒。默认为 0 ,根据自己应用来设置

启动项目测试

# 初始化一个 ThreadPoolTaskScheduler 任务调度器
2020-11-30 23:04:51.886  INFO 10936 --- [  restartedMain] o.s.s.c.ThreadPoolTaskScheduler          : Initializing ExecutorService 'taskScheduler'
# 每5s执行一次定时任务
2020-11-30 23:04:55.002  INFO 10936 --- [    summerday-1] com.hyh.task.DemoTask                    : [定时任务第 1 次执行]
2020-11-30 23:05:00.002  INFO 10936 --- [    summerday-1] com.hyh.task.DemoTask                    : [定时任务第 2 次执行]
2020-11-30 23:05:05.002  INFO 10936 --- [    summerday-2] com.hyh.task.DemoTask                    : [定时任务第 3 次执行]
2020-11-30 23:05:10.001  INFO 10936 --- [    summerday-1] com.hyh.task.DemoTask                    : [定时任务第 4 次执行]
2020-11-30 23:05:15.002  INFO 10936 --- [    summerday-3] com.hyh.task.DemoTask                    : [定时任务第 5 次执行]

SpringTask异步任务

SpringTask除了@Scheduled、@EnableScheduling同步定时任务之外,还有@Async、@EnableAsync 开启异步的定时任务调度。

SpringBoot自动配置类对异步的支持:org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration

@Async注解添加

    @Async
    @Scheduled(cron = "0/1 * * * * *")
    public void asyncTask() {
        sleep();
        System.out.println(Thread.currentThread().getName() + " async-task 执行,当前时间: " + LocalDateTime.now());
    }

@EnableAsync注解添加

@Configuration
@EnableScheduling  // 同步
@EnableAsync // 异步
public class ScheduleConfig {

}

配置文件

spring:
  task:
    # Spring 执行器配置,对应 TaskExecutionProperties 配置类。对于 Spring 异步任务,会使用该执行器。
    execution:
      thread-name-prefix: async- # 线程池的线程名的前缀。默认为 task- ,建议根据自己应用来设置
      pool: # 线程池相关
        core-size: 8 # 核心线程数,线程池创建时候初始化的线程数。默认为 8 。
        max-size: 20 # 最大线程数,线程池最大的线程数,只有在缓冲队列满了之后,才会申请超过核心线程数的线程。默认为 Integer.MAX_VALUE
        keep-alive: 60s # 允许线程的空闲时间,当超过了核心线程之外的线程,在空闲时间到达之后会被销毁。默认为 60 秒
        queue-capacity: 200 # 缓冲队列大小,用来缓冲执行任务的队列的大小。默认为 Integer.MAX_VALUE 。
        allow-core-thread-timeout: true # 是否允许核心线程超时,即开启线程池的动态增长和缩小。默认为 true 。
      shutdown:
        await-termination: true # 应用关闭时,是否等待定时任务执行完成。默认为 false ,建议设置为 true
        await-termination-period: 60 # 等待任务完成的最大时长,单位为秒。默认为 0 ,根据自己应用来设置

同步与异步对比

@Component
public class DemoAsyncTask {

    @Scheduled(cron = "0/1 * * * * *")
    public void synTask() {
        sleep();
        System.out.println(Thread.currentThread().getName() + " syn-task 执行,当前时间: " + LocalDateTime.now());
    }

    @Async
    @Scheduled(cron = "0/1 * * * * *")
    public void asyncTask() {
        sleep();
        System.out.println(Thread.currentThread().getName() + " async-task 执行,当前时间: " + LocalDateTime.now());
    }

    private void sleep() {
        try {
            Thread.sleep(10 * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

同时开启同步和异步任务,假设任务本身耗时较长,且间隔较短:间隔1s,执行10s,同步与异步执行的差异就此体现。

SpringBoot中的定时任务的同步与异步你确定真的知道?

 

可以看到,同步任务并没有每间隔1s就执行,而是串行在一起,等前一个任务执行完才执行。而异步任务则不一样,成功将串行化的任务并行化。

原文链接:https://www.cnblogs.com/summerday152/p/14070941.html

如果觉得本文对你有帮助,可以转发关注支持一下



Tags:SpringBoot   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
我是一名程序员关注我们吧,我们会多多分享技术和资源。进来的朋友,可以多了解下青锋的产品,已开源多个产品的架构版本。Thymeleaf版(开源)1、采用技术: springboot、layui、Thymel...【详细内容】
2021-12-14  Tags: SpringBoot  点击:(20)  评论:(0)  加入收藏
前言项目中的配置文件会有密码的存在,例如数据库的密码、邮箱的密码、FTP的密码等。配置的密码以明文的方式暴露,并不是一种安全的方式,特别是大型项目的生产环境中,因为配置文...【详细内容】
2021-11-17  Tags: SpringBoot  点击:(25)  评论:(0)  加入收藏
SpringBoot开发的物联网通信平台系统项目功能模块 功能 说明 MQTT 1.SSL支持 2.集群化部署时暂不支持retain&will类型消 UDP ...【详细内容】
2021-11-05  Tags: SpringBoot  点击:(55)  评论:(0)  加入收藏
1. 介绍1.1 介绍今天开始我们来学习Java操作MySQL数据库的技巧,Java操作MySQL是借助JdbcTemplate这个对象来实现的。JdbcTemplate是一个多数据库集中解决方案,而我们今天只讲...【详细内容】
2021-11-05  Tags: SpringBoot  点击:(30)  评论:(0)  加入收藏
SpringBoot中的Controller注册本篇将会以Servlet为切入点,通过源码来看web容器中的Controller是如何注册到HandlerMapping中。请求来了之后,web容器是如何根据请求路径找到对...【详细内容】
2021-11-04  Tags: SpringBoot  点击:(52)  评论:(0)  加入收藏
环境:Springboot2.4.11环境配置接下来的演示都是基于如下接口进行。@RestController@RequestMapping("/exceptions")public class ExceptionsController { @GetMapping(...【详细内容】
2021-10-11  Tags: SpringBoot  点击:(41)  评论:(0)  加入收藏
SpringBoot项目默认使用logback, 已经内置了 logback 的相关jar包,会从resource包下查找logback.xml, logback 文件格式范本 可直接复制使用,有控制台 info.log error.log三个...【详细内容】
2021-10-09  Tags: SpringBoot  点击:(50)  评论:(0)  加入收藏
环境:Springboot2.4.10当应用程序启动时,Spring Boot将自动从以下位置查找并加载application.properties和application.yaml文件: 从Classpath类路径classpath的根类路径classp...【详细内容】
2021-09-26  Tags: SpringBoot  点击:(76)  评论:(0)  加入收藏
搭建基础1. Intellij IDEA 2. jdk1.8 3. maven3.6.3搭建方式(1)在线创建项目Spring Boot 官方提供的一种创建方式,在浏览器中访问如下网址: https://start.spring.io/在打开的页...【详细内容】
2021-09-14  Tags: SpringBoot  点击:(78)  评论:(0)  加入收藏
最近开发项目的时候需要用到对象的属性拷贝,以前也有用过一些复制框架,比如spring的 BeanUtils.copyProperties等方式,但总是不尽如人意,最近发现使用orika进行对象拷贝挺好用的...【详细内容】
2021-08-27  Tags: SpringBoot  点击:(231)  评论:(0)  加入收藏
▌简易百科推荐
近日只是为了想尽办法为 Flask 实现 Swagger UI 文档功能,基本上要让 Flask 配合 Flasgger, 所以写了篇 Flask 应用集成 Swagger UI 。然而不断的 Google 过程中偶然间发现了...【详细内容】
2021-12-23  Python阿杰    Tags:FastAPI   点击:(6)  评论:(0)  加入收藏
文章目录1、Quartz1.1 引入依赖<dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.3.2</version></dependency>...【详细内容】
2021-12-22  java老人头    Tags:框架   点击:(11)  评论:(0)  加入收藏
今天来梳理下 Spring 的整体脉络啦,为后面的文章做个铺垫~后面几篇文章应该会讲讲这些内容啦 Spring AOP 插件 (了好久都忘了 ) 分享下 4ye 在项目中利用 AOP + MybatisPlus 对...【详细内容】
2021-12-07  Java4ye    Tags:Spring   点击:(14)  评论:(0)  加入收藏
&emsp;前面通过入门案例介绍,我们发现在SpringSecurity中如果我们没有使用自定义的登录界面,那么SpringSecurity会给我们提供一个系统登录界面。但真实项目中我们一般都会使用...【详细内容】
2021-12-06  波哥带你学Java    Tags:SpringSecurity   点击:(18)  评论:(0)  加入收藏
React 简介 React 基本使用<div id="test"></div><script type="text/javascript" src="../js/react.development.js"></script><script type="text/javascript" src="../js...【详细内容】
2021-11-30  清闲的帆船先生    Tags:框架   点击:(19)  评论:(0)  加入收藏
流水线(Pipeline)是把一个重复的过程分解为若干个子过程,使每个子过程与其他子过程并行进行的技术。本文主要介绍了诞生于云原生时代的流水线框架 Argo。 什么是流水线?在计算机...【详细内容】
2021-11-30  叼着猫的鱼    Tags:框架   点击:(21)  评论:(0)  加入收藏
TKinterThinter 是标准的python包,你可以在linx,macos,windows上使用它,你不需要安装它,因为它是python自带的扩展包。 它采用TCL的控制接口,你可以非常方便地写出图形界面,如...【详细内容】
2021-11-30    梦回故里归来  Tags:框架   点击:(26)  评论:(0)  加入收藏
前言项目中的配置文件会有密码的存在,例如数据库的密码、邮箱的密码、FTP的密码等。配置的密码以明文的方式暴露,并不是一种安全的方式,特别是大型项目的生产环境中,因为配置文...【详细内容】
2021-11-17  充满元气的java爱好者  博客园  Tags:SpringBoot   点击:(25)  评论:(0)  加入收藏
一、搭建环境1、创建数据库表和表结构create table account(id INT identity(1,1) primary key,name varchar(20),[money] DECIMAL2、创建maven的工程SSM,在pom.xml文件引入...【详细内容】
2021-11-11  AT小白在线中  搜狐号  Tags:开发框架   点击:(29)  评论:(0)  加入收藏
SpringBoot开发的物联网通信平台系统项目功能模块 功能 说明 MQTT 1.SSL支持 2.集群化部署时暂不支持retain&will类型消 UDP ...【详细内容】
2021-11-05  小程序建站    Tags:SpringBoot   点击:(55)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条