返回顶部
首页 > 资讯 > 精选 >SpringBoot定时任务功能怎么实现
  • 639
分享到

SpringBoot定时任务功能怎么实现

2023-06-30 14:06:42 639人浏览 独家记忆
摘要

本篇内容介绍了“SpringBoot定时任务功能怎么实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一 背景项目中需要一个可以动态新增定时

本篇内容介绍了“SpringBoot定时任务功能怎么实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

一 背景

项目中需要一个可以动态新增定时定时任务的功能,现在项目中使用的是xxl-job定时任务调度系统,但是经过一番对xxl-job功能的了解,发现xxl-job对项目动态新增定时任务,动态删除定时任务的支持并不是那么好,所以需要自己手动实现一个定时任务的功能

二 动态定时任务调度

1 技术选择

Timer or ScheduledExecutorService

这两个都能实现定时任务调度,先看下Timer的定时任务调度

  public class MyTimerTask extends TimerTask {    private String name;    public MyTimerTask(String name){        this.name = name;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    @Override    public void run() {        //task        Calendar instance = Calendar.getInstance();        System.out.println(new SimpleDateFORMat("yyyy-MM-dd HH:mm:ss").format(instance.getTime()));    }}Timer timer = new Timer();MyTimerTask timerTask = new MyTimerTask("NO.1");//首次执行,在当前时间的1秒以后,之后每隔两秒钟执行一次timer.schedule(timerTask,1000L,2000L);

在看下ScheduledThreadPoolExecutor的实现

//org.apache.commons.lang3.concurrent.BasicThreadFactoryScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1,    new BasicThreadFactory.Builder().namingPattern("example-schedule-pool-%d").daemon(true).build());executorService.scheduleAtFixedRate(new Runnable() {    @Override    public void run() {        //do something    }},initialDelay,period, TimeUnit.HOURS);

两个都能实现定时任务,那他们的区别呢,使用阿里p3c会给出建议和区别

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

从建议上来看,是一定要选择ScheduledExecutorService了,我们看看源码看看为什么Timer出现问题会终止执行

private final TimerThread thread = new TimerThread(queue);public Timer() {    this("Timer-" + serialNumber());}public Timer(String name) {    thread.setName(name);    thread.start();}

新建对象时,我们看到开启了一个线程,那么这个线程在做什么呢?一起看看

class TimerThread extends Thread {  boolean newTasksMayBeScheduled = true;    private TaskQueue queue;  TimerThread(TaskQueue queue) {      this.queue = queue;  }  public void run() {      try {          mainLoop();      } finally {          // Someone killed this Thread, behave as if Timer cancelled          synchronized(queue) {              newTasksMayBeScheduled = false;              queue.clear();  // 清除所有任务信息          }      }  }    private void mainLoop() {      while (true) {          try {              TimerTask task;              boolean taskFired;              synchronized(queue) {                  // Wait for queue to become non-empty                  while (queue.isEmpty() && newTasksMayBeScheduled)                      queue.wait();                  if (queue.isEmpty())                      break; // Queue is empty and will forever remain; die                  // Queue nonempty; look at first evt and do the right thing                  long currentTime, executionTime;                  task = queue.getMin();                  synchronized(task.lock) {                      if (task.state == TimerTask.CANCELLED) {                          queue.removeMin();                          continue;  // No action required, poll queue again                      }                      currentTime = System.currentTimeMillis();                      executionTime = task.nextExecutionTime;                      if (taskFired = (executionTime<=currentTime)) {                          if (task.period == 0) { // Non-repeating, remove                              queue.removeMin();                              task.state = TimerTask.EXECUTED;                          } else { // Repeating task, reschedule                              queue.rescheduleMin(                                task.period<0 ? currentTime   - task.period                                              : executionTime + task.period);                          }                      }                  }                  if (!taskFired) // Task hasn't yet fired; wait                      queue.wait(executionTime - currentTime);              }              if (taskFired)  // Task fired; run it, holding no locks                  task.run();          } catch(InterruptedException e) {          }      }  }}

我们看到,执行了 mainLoop(),里面是 while (true)方法无限循环,获取程序中任务对象中的时间和当前时间比对,相同就执行,但是一旦报错,就会进入finally中清除掉所有任务信息。

这时候我们已经找到了答案,timer是在被实例化后,启动一个线程,不间断的循环匹配,来执行任务,他是单线程的,一旦报错,线程就终止了,所以不会执行后续的任务,而ScheduledThreadPoolExecutor是多线程执行的,就算其中有一个任务报错了,并不影响其他线程的执行。

2 使用ScheduledThreadPoolExecutor

从上面看,使用ScheduledThreadPoolExecutor还是比较简单的,但是我们要实现的更优雅一些,所以选择 TaskScheduler来实现

@Componentpublic class CronTaskReGIStrar implements DisposableBean {    private final Map<Runnable, ScheduledTask> scheduledTasks = new ConcurrentHashMap<>(16);    @Autowired    private TaskScheduler taskScheduler;    public TaskScheduler getScheduler() {        return this.taskScheduler;    }    public void addCronTask(Runnable task, String cronExpression) {        addCronTask(new CronTask(task, cronExpression));    }    private void addCronTask(CronTask cronTask) {        if (cronTask != null) {            Runnable task = cronTask.getRunnable();            if (this.scheduledTasks.containsKey(task)) {                removeCronTask(task);            }            this.scheduledTasks.put(task, scheduleCronTask(cronTask));        }    }    public void removeCronTask(Runnable task) {        Set<Runnable> runnables = this.scheduledTasks.keySet();        Iterator it1 = runnables.iterator();        while (it1.hasNext()) {            SchedulingRunnable schedulingRunnable = (SchedulingRunnable) it1.next();            Long taskId = schedulingRunnable.getTaskId();            SchedulingRunnable cancelRunnable = (SchedulingRunnable) task;            if (taskId.equals(cancelRunnable.getTaskId())) {                ScheduledTask scheduledTask = this.scheduledTasks.remove(schedulingRunnable);                if (scheduledTask != null){                    scheduledTask.cancel();                }            }        }    }    public ScheduledTask scheduleCronTask(CronTask cronTask) {        ScheduledTask scheduledTask = new ScheduledTask();        scheduledTask.future = this.taskScheduler.schedule(cronTask.getRunnable(), cronTask.getTrigger());        return scheduledTask;    }    @Override    public void destroy() throws Exception {        for (ScheduledTask task : this.scheduledTasks.values()) {            task.cancel();        }        this.scheduledTasks.clear();    }}

TaskScheduler是本次功能实现的核心类,但是他是一个接口

public interface TaskScheduler {      @Nullable   ScheduledFuture<?> schedule(Runnable task, Trigger trigger);

前面的代码可以看到,我们在类中注入了这个类,但是他是接口,我们怎么知道是那个实现类呢,以往出现这种情况要在类上面加@Primany或者@Quality来执行实现的类,但是我们看到我的注入上并没有标记,因为是通过另一种方式实现的

@Configurationpublic class SchedulinGConfig {    @Bean    public TaskScheduler taskScheduler() {        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();        // 定时任务执行线程池核心线程数        taskScheduler.setPoolSize(4);        taskScheduler.setRemoveOnCancelPolicy(true);        taskScheduler.setThreadNamePrefix("TaskSchedulerThreadPool-");        return taskScheduler;    }}

spring初始化时就注册了Bean TaskScheduler,而我们可以看到他的实现是ThreadPoolTaskScheduler,在网上的资料中有人说ThreadPoolTaskScheduler是TaskScheduler的默认实现类,其实不是,还是需要我们去指定,而这种方式,当我们想替换实现时,只需要修改配置类就行了,很灵活。

而为什么说他是更优雅的实现方式呢,因为他的核心也是通过ScheduledThreadPoolExecutor来实现的

public ScheduledExecutorService getScheduledExecutor() throws IllegalStateException {   Assert.state(this.scheduledExecutor != null, "ThreadPoolTaskScheduler not initialized");   return this.scheduledExecutor;}

三 多节点任务执行问题

这次的实现过程中,我并没有选择xxl-job来进行实现,而是采用了TaskScheduler来实现,这也产生了一个问题,xxl-job是分布式的程序调度系统,当想要执行定时任务的应用使用xxl-job时,无论应用程序中部署多少个节点,xxl-job只会选择其中一个节点作为定时任务执行的节点,从而不会产生定时任务在不同节点上同时执行,导致重复执行问题,而使用TaskScheduler来实现,就要考虑多节点重复执行问题。当然既然有问题,就有解决方案

&middot; 方案一 将定时任务功能拆出来单独部署,且只部署一个节点 &middot; 方案二 使用redis setNx的形式,保证同一时间只有一个任务在执行

我选择的是方案二来执行,当然还有一些方式也能保证不重复执行,这里就不多说了,一下是我的实现

public void executeTask(Long taskId) {    if (!RedisService.setIfAbsent(String.valueOf(taskId),"1",2L, TimeUnit.SECONDS)) {        log.info("已有执行中定时发送短信任务,本次不执行!");        return;    }

“SpringBoot定时任务功能怎么实现”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

--结束END--

本文标题: SpringBoot定时任务功能怎么实现

本文链接: https://lsjlt.com/news/329621.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • SpringBoot定时任务功能怎么实现
    本篇内容介绍了“SpringBoot定时任务功能怎么实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一 背景项目中需要一个可以动态新增定时...
    99+
    2023-06-30
  • 怎么用SpringBoot实现动态添加定时任务功能
    这篇“怎么用SpringBoot实现动态添加定时任务功能”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“怎么用SpringBo...
    99+
    2023-06-29
  • SpringBoot 实现动态添加定时任务功能
    目录代码结构1. 配置类2. 定时任务类型枚举3. 实际执行任务实现类4. 定时任务包装器5. 任务注册器 (核心)6. 使用最后最近的需求有一个自动发布的功能, 需要做到每次提交都...
    99+
    2024-04-02
  • SpringBoot定时任务怎么实现
    这篇文章主要讲解了“SpringBoot定时任务怎么实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“SpringBoot定时任务怎么实现”吧!SpringBoot定时任务主要由两个注解完成...
    99+
    2023-06-05
  • 详解SpringBoot定时任务功能
    目录一 背景二 动态定时任务调度三 多节点任务执行问题四 后记一 背景 项目中需要一个可以动态新增定时定时任务的功能,现在项目中使用的是xxl-job定时任务调度系统,但是经过一番对...
    99+
    2024-04-02
  • Android实现定时任务功能
    本文实例为大家分享了Android实现定时任务功能的具体代码,供大家参考,具体内容如下 1、采用Handle与线程的sleep(long)方法 (1)、定义一个Handler类,用于...
    99+
    2024-04-02
  • SpringBoot实现quartz定时任务可视化管理功能
    前言 在实际框架或产品开发过程中,springboot中集成quarzt方式基本是以job和trigger的bean对象方式直接硬编码完成的,例如以下代码示例。对于系统内定义的所有定...
    99+
    2024-04-02
  • springboot定时任务和异步任务怎么实现
    这篇文章主要介绍“springboot定时任务和异步任务怎么实现”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“springboot定时任务和异步任务怎么实现”文章能帮助大家解决问题。异步任务简单案例...
    99+
    2023-06-27
  • Java中怎么实现SpringBoot定时任务
    今天就跟大家聊聊有关Java中怎么实现SpringBoot定时任务,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。1. SpringBoot--任务:定时任务项目开发中经常需要执行一些...
    99+
    2023-06-20
  • Springboot怎么通过Scheduled实现定时任务
    小编给大家分享一下Springboot怎么通过Scheduled实现定时任务,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!定时任务一般会存在中大型企业级项目中,为...
    99+
    2023-05-30
    springboot
  • SpringBoot怎么使用Schedule实现定时任务
    本文小编为大家详细介绍“SpringBoot怎么使用Schedule实现定时任务”,内容详细,步骤清晰,细节处理妥当,希望这篇“SpringBoot怎么使用Schedule实现定时任务”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一...
    99+
    2023-07-05
  • Springboot如何实现定时任务
    这篇文章给大家分享的是有关Springboot如何实现定时任务的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。定时任务此处的定时,标注在方法上+注解,假如想修改生成环境的时间,不是很灵活,后面补充Quartz+bo...
    99+
    2023-06-17
  • 如何在springboot中利用Quartz实现一个定时任务功能
    如何在springboot中利用Quartz实现一个定时任务功能?相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。一、新建一个springboot工程,并添加依赖<depen...
    99+
    2023-05-31
    springboot art quartz
  • SpringBoot+Quartz实现动态定时任务
    本文实例为大家分享了springBoot+Quartz实现动态定时任务的具体代码,供大家参考,具体内容如下 目前常用的几种任务调度 Timer,简单无门槛,一般也没人用。spring...
    99+
    2024-04-02
  • SpringBoot-定时任务
    在我们实际开发项目的过程中,经常需要定时任务来帮我们做一些事情,例如每隔一小时统计新注册的用户数量、每天凌晨一点进行服务器缓存清理、每周五统计购买会员的用户数量等。SpringBoot在2.0版本之后,提供了非常方便的注解方式来编写定时任务...
    99+
    2014-06-07
    java教程 SpringBoot
  • 怎么用ajax实现实时任务提示功能
    这篇文章主要介绍“怎么用ajax实现实时任务提示功能”,在日常操作中,相信很多人在怎么用ajax实现实时任务提示功能问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么用aja...
    99+
    2024-04-02
  • springboot定时任务怎么创建
    如果你想了解更多关于springboot的知识,可以点击:JAVA教程使用SpringBoot创建定时任务非常简单,目前主要有以下三种创建方式:  一、基于注解(@Scheduled)  二、基于接口(SchedulingConfigure...
    99+
    2021-09-19
    java教程 SpringBoot
  • SpringBoot定时任务怎么使用
    在Spring Boot中使用定时任务,可以按照以下步骤进行操作:1. 在pom.xml文件中添加Spring Boot的定时任务依...
    99+
    2023-08-15
    SpringBoot
  • SpringBoot动态定时任务如何实现
    这篇文章主要介绍了SpringBoot动态定时任务如何实现的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇SpringBoot动态定时任务如何实现文章都会有所收获,下面我们一起来看看吧。 执行定时任务的...
    99+
    2023-07-05
  • SpringBoot结合XXL-JOB实现定时任务
    《从零打造项目》系列文章 工具 比MyBatis Generator更强大的代码生成器 ORM框架选型 SpringBoot项目基础设施搭建SpringBoot集成Mybatis项目实操SpringBoot集成Mybatis Pl...
    99+
    2023-08-16
    spring boot java mybatis
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作