教你优雅的实现 SpringBoot 并行任务

Spring Boot 实现异步处理多个并行任务 在现代Web应用开发中,异步处理和多任务并行处理对于提高系统的响应性和吞吐量至关重要。Spring Boot 提供了多种机制来实现异步任务处理,本文将介绍如何利用这些机制来优化您的应用程序性能。 阅读详情

欢迎关注方志朋的博客,回复”666“获面试宝典

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);
 }
}

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

@Scheduled中的参数说明:

  • @Scheduled(fixedRate=2000):上一次开始执行时间点后2秒再次执行;

  • @Scheduled(fixedDelay=2000):上一次执行完毕时间点后2秒再次执行;

  • @Scheduled(initialDelay=1000, fixedDelay=2000):第一次延迟1秒执行,然后在上一次执行完毕时间点后2秒再次执行;

  • @Scheduled(cron="* * * * * ?"):按cron规则执行。

在线Cron表达式生成器:http://cron.qqe2.com/

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

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观察执行结果:

c5f28effdf22fe8a065684d72b333413.png

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

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、执行结果(并发)
6706a560049f176356462ba2e7d40cc7.png

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

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

热门内容:

 

fbff66644f26d875046460f7a582e894.jpeg


 
最近面试BAT,整理一份面试资料《Java面试BAT通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。
获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。

明天见(。・ω・。)ノ

numeca linux 11,NUMECA FINE/Turbo16下载-NUMECA FINE/Turbo16官方版v16.0 最新版 - 起点软件园... NUMECA FINE/Turbo16,空气动力学模拟工具,帮助小伙伴随时仿真模拟,让小伙伴可以模拟出最真实的环境,让小伙伴可以轻松完成环境模拟的服务,帮助小伙伴更好的解决自己的课题研究!NUMECA FINE/Turbo16说明1、支持在64位WINDOWS操作系统和LINUX操作系统下运行2、基于全二阶精度的数值格式,保证了计算精度3、采用先进的全多重网格技术和基于密度的求解方法保证了快速的流... 阅读详情

相关推荐

智能车图像处理14-进阶篇6--坡道的判定

这篇文章主要讲述智能车图像处理中 : 如何判断坡道

taiyuezyh的博客 9157

SpringBoot 多任务并行+线程池处理的实现

主要介绍了SpringBoot 多任务并行+线程池处理的实现,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

springboot 定时任务(线程配置,并行【同步】、异步等)

springboot 定时任务(线程配置,并行【同步】、异步等)

springboot使用多线程采集for循环并把结果合并集合的方法

欢迎使用Markdown编辑器 你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。 新的改变 我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客: 全新的界面设计 ,将会带来全新的写作体验; 在创作中心设置你喜爱的代码高亮样式,Markdown 将代码片显示选择的高亮样式 进行展示; 增加了 图片

u011684553的博客 3243

SpringBoot异步任务及并行事务实现

SpringBoot异步任务及并行事务实现

Infinite Progress 6725

SpringBoot整合SpringBatch实例(多任务, 并行, 串行)

在childJobOneStep()方法中,通过JobStepBuilder构建了一个名称为childJobOneStep的Step,顾名思义,它是一个任务型Step的构造工厂,可以将任务转换为“特殊”的步骤。chunk字面上的意思是“块”的意思,可以简单理解为数据块,泛型用于指定读取的数据和输出的数据类型,构造器入参指定了数据块的大小,比如指定为2时表示每当读取2组数据后做一次数据输出处理。Chunk里面就是不断循环的一个流程,读数据,处理数据,然后写数据。

justlpf的专栏 4762

Spring Boot 定时任务单线程和多线程

Spring Boot 的定时任务: 第一种:把参数配置到.properties文件中: 代码: package com.accord.task; import java.text.SimpleDateFormat; import java.util.Date; import org.springframework.scheduling.annotation.Scheduled; imp

u013456370的专栏 8万+

Spring Boot 实现程序的优雅退出

在服务器环境中,确保应用程序能够平滑关闭并处理完所有现有请求是一个重要的需求。Spring Boot 为我们提供了优雅退出的功能,使应用程序能够在关闭时正常处理完所有当前请求,避免请求被中断导致数据丢失或不一致等问题。本文将全面介绍如何在 Spring Boot 应用程序中实现优雅退出。

qq_35716689的博客 25万+

springboot 多线程实现

有时候,,如果,系统就要,有时会。而且当线程数量太多时,

m0_67402970的博客 1589

springboot之多任务并行+线程池处理

最近项目中做到一个关于批量发短信的业务,如果用户量特别大的话,不能使用单线程去发短信,只能尝试着使用多任务来完成!我们的项目使用到了方式二,即Future的方案 Java 线程池 Java通过Executors提供四种线程池,分别为: newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。 newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。 newSche.

YHJ 6803

Springboot 并发执行多任务

在上述示例代码中,我们通过 ThreadPoolExecutor 类创建一个最大线程数为 10,任务队列容量为 100 的线程池。当访问 /tasks URL 时,添加两个任务到线程池中。时,就会并发地执行两个任务。线程池会自动管理线程的数量、任务队列和线程的生命周期。如果需要执行更多任务,只需添加更多的任务到线程池中即可。如果想要一次性并发执行多个任务,可以使用 Java 并发编程中的线程池来实现。// 添加 2 个任务到线程池中。

1401

FANUC机器人PROFINET通信(新版)资料汇总-含GSD+手册等.rar

FANUC机器人PROFINET通信(新版)资料汇总_含GSD+手册等

上一篇: 国内怎么就做不出 JetBrains 那样的产品?
下一篇: MyBatis-Plus 使用这么方便,底层是如何处理的呢?
公众号:方志朋
博客等级 码龄5年 307粉丝 94原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值