首页 > 其他分享 >Spring Boot 并行任务,这才是优雅的实现方式!

Spring Boot 并行任务,这才是优雅的实现方式!

时间:2022-10-26 14:44:27浏览次数:82  
标签:Scheduled Spring Boot 任务 并行任务 org import 定时 public

Spring Boot 的定时任务:

第一种:把参数配置到.properties文件中:

代码:

package com.accord.task;
 
import java.text.SimpleDateFormat;
import java.util.Date;
 
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
 
/**
 * 从配置文件加载任务信息
 * @author 王久印
 */
@Component
public class ScheduledTask {
 
  private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
 
  //@Scheduled(fixedDelayString = "${jobs.fixedDelay}")
  @Scheduled(fixedDelayString = "2000")
  public void getTask1() {
    System.out.println("任务1,从配置文件加载任务信息,当前时间:" + dateFormat.format(new Date()));
  }
 
  @Scheduled(cron = "${jobs.cron}")
  public void getTask2() {
    System.out.println("任务2,从配置文件加载任务信息,当前时间:" + dateFormat.format(new Date()));
  }
}

application.properties文件:

jobs.fixedDelay=5000
jobs.cron=0/5 * *  * * ?

SpringBootCron2Application.java中:

package com.accord;
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
 
@SpringBootApplication
@EnableScheduling
public class SpringBootCron2Application {
 public static void main(String[] args) {
  SpringApplication.run(SpringBootCron2Application.class, args);
 }
}

Spring Boot 基础就不介绍了,推荐看这个免费教程:

https://github.com/javastacks/spring-boot-best-practice

注:@EnableScheduling 这个一定要加上;否则,不会定时启动任务!

@Scheduled中的参数说明:

  • @Scheduled(fixedRate=2000):上一次开始执行时间点后2秒再次执行;
  • @Scheduled(fixedDelay=2000):上一次执行完毕时间点后2秒再次执行;
  • @Scheduled(initialDelay=1000, fixedDelay=2000):第一次延迟1秒执行,然后在上一次执行完毕时间点后2秒再次执行;
  • @Scheduled(cron="* * * * * ?"):按cron规则执行。

第二种定时任务:单线程和多线程

1、创建定时任务:

package com.accord.task;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
 
/**
 * 构建执行定时任务
 * @author 王久印
 * TODO
 */
@Component
public class ScheduledTask2 {
 
    private Logger logger = LoggerFactory.getLogger(ScheduledTask2.class);
 
    private int fixedDelayCount = 1;
    private int fixedRateCount = 1;
    private int initialDelayCount = 1;
    private int cronCount = 1;
 
    @Scheduled(fixedDelay = 5000)        //fixedDelay = 5000表示当前方法执行完毕5000ms后,Spring scheduling会再次调用该方法
    public void testFixDelay() {
        logger.info("===fixedDelay: 第{}次执行方法", fixedDelayCount++);
    }
 
    @Scheduled(fixedRate = 5000)        //fixedRate = 5000表示当前方法开始执行5000ms后,Spring scheduling会再次调用该方法
    public void testFixedRate() {
        logger.info("===fixedRate: 第{}次执行方法", fixedRateCount++);
    }
 
    @Scheduled(initialDelay = 1000, fixedRate = 5000)   //initialDelay = 1000表示延迟1000ms执行第一次任务
    public void testInitialDelay() {
        logger.info("===initialDelay: 第{}次执行方法", initialDelayCount++);
    }
 
    @Scheduled(cron = "0 0/1 * * * ?")  //cron接受cron表达式,根据cron表达式确定定时规则
    public void testCron() {
        logger.info("===initialDelay: 第{}次执行方法", cronCount++);
    }
 
}

使用 @Scheduled来创建定时任务 这个注解用来标注一个定时任务方法。

通过看 @Scheduled源码可以看出它支持多种参数:

  • cron:cron表达式,指定任务在特定时间执行;
  • fixedDelay:表示上一次任务执行完成后多久再次执行,参数类型为long,单位ms;
  • fixedDelayString:与fixedDelay含义一样,只是参数类型变为String;
  • fixedRate:表示按一定的频率执行任务,参数类型为long,单位ms;
  • fixedRateString: 与fixedRate的含义一样,只是将参数类型变为String;
  • initialDelay:表示延迟多久再第一次执行任务,参数类型为long,单位ms;
  • initialDelayString:与initialDelay的含义一样,只是将参数类型变为String;
  • zone:时区,默认为当前时区,一般没有用到。

2、开启定时任务:

package com.accord;
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
 
@SpringBootApplication
@EnableScheduling
public class SpringBootCron2Application {
 public static void main(String[] args) {
  SpringApplication.run(SpringBootCron2Application.class, args);
 }
}

注:这里的 @EnableScheduling 注解,它的作用是发现注解 @Scheduled的任务并由后台执行。没有它的话将无法执行定时任务。

引用官方文档原文:

@EnableScheduling ensures that a background task executor is created. Without it, nothing gets scheduled.

3、执行结果(单线程)

就完成了一个简单的定时任务模型,下面执行springBoot观察执行结果:

从控制台输入的结果中我们可以看出所有的定时任务都是在同一个线程池用同一个线程来处理的,那么我们如何来并发的处理各定时任务呢,请继续向下看。

4、多线程处理定时任务:

看到控制台输出的结果,所有的定时任务都是通过一个线程来处理的,我估计是在定时任务的配置中设定了一个SingleThreadScheduledExecutor,于是我看了源码,从ScheduledAnnotationBeanPostProcessor类开始一路找下去。果然,在ScheduledTaskRegistrar(定时任务注册类)中的ScheduleTasks中又这样一段判断:

if (this.taskScheduler == null) {
 this.localExecutor = Executors.newSingleThreadScheduledExecutor();
 this.taskScheduler = new ConcurrentTaskScheduler(this.localExecutor);
}

这就说明如果taskScheduler为空,那么就给定时任务做了一个单线程的线程池,正好在这个类中还有一个设置taskScheduler的方法:

public void setScheduler(Object scheduler) {
 Assert.notNull(scheduler, "Scheduler object must not be null");
 if (scheduler instanceof TaskScheduler) {
  this.taskScheduler = (TaskScheduler) scheduler;
 }
 else if (scheduler instanceof ScheduledExecutorService) {
  this.taskScheduler = new ConcurrentTaskScheduler(((ScheduledExecutorService) scheduler));
 }
 else {
  throw new IllegalArgumentException("Unsupported scheduler type: " + scheduler.getClass());
 }
}

这样问题就很简单了,我们只需用调用这个方法显式的设置一个ScheduledExecutorService就可以达到并发的效果了。我们要做的仅仅是实现SchedulingConfigurer接口,重写configureTasks方法就OK了;

package com.accord.task;
 
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
 
import java.util.concurrent.Executors;
 
/**
 * 多线程执行定时任务
 * @author 王久印
 */
@Configuration
//所有的定时任务都放在一个线程池中,定时任务启动时使用不同都线程。
public class ScheduleConfig implements SchedulingConfigurer {
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        //设定一个长度10的定时任务线程池
        taskRegistrar.setScheduler(Executors.newScheduledThreadPool(10));
    }
}

5、执行结果(并发)

通过控制台输出的结果看出每个定时任务都是在通过不同的线程来处理了。

来源:wangjiuyin.blog.csdn.net/article/details/79411952

近期热文推荐:

1.1,000+ 道 Java面试题及答案整理(2022最新版)

2.劲爆!Java 协程要来了。。。

3.Spring Boot 2.x 教程,太全了!

4.别再写满屏的爆爆爆炸类了,试试装饰器模式,这才是优雅的方式!!

5.《Java开发手册(嵩山版)》最新发布,速速下载!

觉得不错,别忘了随手点赞+转发哦!

标签:Scheduled,Spring,Boot,任务,并行任务,org,import,定时,public
From: https://www.cnblogs.com/javastack/p/16828318.html

相关文章

  • SpringMVC学习笔记--wsdchong
    前言:SpringMVC入门、SpringMVC数据绑定、JSON数据交互和RESTful支持、拦截器、SSM框架整合、一、SpringMVC入门1SpringMVC是spring提供的一个轻量级web框架,实现了webMVC设计......
  • Spring学习笔记--wsdchong
    前言:理解了基础,就去用轮子,用熟了轮子就再了解基础,然后造轮子。Spring基础、spring的bean、springAOP、spring的数据库开发、spring的事务管理 一、spring基础概念:1spring......
  • 基于springboot+vue商品推荐管理系统的设计与实现(源码调试+讲解+文档)
    ......
  • spring cloud 加密解密
    1.底包<dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-rsa</artifactId></dependency>RsaSecretEncryptor 类......
  • 部署spingboot项目到云服务器踩坑记录
    按教程部署mall电商系统https://www.macrozheng.com/mall/deploy/mall_deploy_docker.html#docker环境安装只记录SpringBoot应用部署这部分一、本地电脑安装maven官......
  • 【Java技术总结】Spring事务失效总结
    事务方法必须是public,private、protected、default都会失效。@ServicepublicclassUserService{@Transactionalprivatevoidadd(UserModeluserModel){......
  • 使用Spring AOP实现系统操作日志记录
    使用SpringAOP实现系统操作日志记录一、什么是SpringSpring是一个广泛应用的J2EE框架,是针对bean的生命周期进行管理的轻量级容器,主要由SpringCore、SpringAOP、Spri......
  • SpringBoot整合Swagger3
    1、导入相关依赖<!--swagger--><dependency> <groupId>io.springfox</groupId> <artifactId>springfox-boot-starter</artifactId> <version>3.0.0</version></depen......
  • Spring基础使用四
    Spring基础使用四FactoryBean概念:FactoryBean是一个接口,需要创建一个类实现该接口其中有三个方法:getObject():通过一个对象交给IOC容器处理getObjectType():设置......
  • SpringBoot整合Freemarker实现页面静态化
    第一步:创建项目添加依赖:<!--web和actuator(图形监控用)基本上都是一起出现的--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-......