【定时任务】SpringBoot多线程并发动态执行定时任务
通过读取数据库的方式来进行定时任务信息获取,再通过多线程进行并发动态执行!
一、创建业务表
CREATE TABLE `scheduled_task` (`id` int(11) NOT NULL AUTO_INCREMENT,`task_key` varchar(128) DEFAULT NULL COMMENT '任务key值(使用bean名称)',`task_desc` varchar(128) DEFAULT NULL COMMENT '任务描述',`task_cron` varchar(128) DEFAULT NULL COMMENT '任务表达式',`init_start_flag` int(2) DEFAULT '1' COMMENT '程序初始化是否启动 1 是 0 否',`create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',`update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',PRIMARY KEY (`id`),UNIQUE KEY `uniqu_task_key` (`task_key`)
) ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=utf8;
二、插入数据
INSERT INTO `scheduled_task`(`id`, `task_key`, `task_desc`, `task_cron`, `init_start_flag`, `create_time`, `update_time`) VALUES (1, 'scheduledTask01', '定时任务01', '0/5 * * * * ?', 1, NOW(), NOW());
INSERT INTO `scheduled_task`(`id`, `task_key`, `task_desc`, `task_cron`, `init_start_flag`, `create_time`, `update_time`) VALUES (2, 'scheduledTask02', '定时任务02', '0/2 * * * * ?', 0, NOW(), NOW());
INSERT INTO `scheduled_task`(`id`, `task_key`, `task_desc`, `task_cron`, `init_start_flag`, `create_time`, `update_time`) VALUES (3, 'scheduledTask03', '定时任务03', '0/2 * * * * ?', 1, NOW(), NOW());
三、SpringBoot启动类添加相应注解
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;/*** @author lzw* @create 2022-07-14-9:30*/
@SpringBootApplication
@EnableScheduling
@MapperScan("cn.sdata.mapper")
public class SpringBootController {public static void main(String[] args) {SpringApplication.run(SpringBootController.class,args);}
}
四、定时任务执行核心实现类
import cn.sdata.entity.LogTask;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.CronTask;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.stereotype.Component;import javax.annotation.PreDestroy;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledFuture;@Component
public class ScheduledTask implements SchedulingConfigurer {private static volatile ScheduledTaskRegistrar registrar;private static volatile ConcurrentHashMap<Integer, ScheduledFuture<?>> scheduledFutures = new ConcurrentHashMap<Integer, ScheduledFuture<?>>();private static volatile ConcurrentHashMap<Integer, CronTask> cronTasks = new ConcurrentHashMap<Integer, CronTask>();@Overridepublic void configureTasks(ScheduledTaskRegistrar registrar) {//设置20个线程,默认单线程registrar.setScheduler(Executors.newScheduledThreadPool(20));this.registrar = registrar;}public void refresh(List<LogTask> tasks){//取消已经删除的策略任务Set<Integer> sids = scheduledFutures.keySet();for (Integer sid : sids) {if(!exists(tasks, sid)){scheduledFutures.get(sid).cancel(false);}}for (LogTask logTask : tasks) {
// ScheduledTaskRunnable t = new ScheduledTaskRunnable(logTask.getTask_id(), logTask.getRule_db_id());String expression = logTask.getExpression();//计划任务表达式为空则跳过if(StringUtils.isEmpty(expression)){continue;}//计划任务已存在并且表达式未发生变化则跳过if(scheduledFutures.containsKey(logTask.getTask_id()) && cronTasks.get(logTask.getTask_id()).getExpression().equals(expression)){continue;}//如果策略执行时间发生了变化,则取消当前策略的任务if(scheduledFutures.containsKey(logTask.getTask_id())){scheduledFutures.get(logTask.getTask_id()).cancel(false);scheduledFutures.remove(logTask.getTask_id());cronTasks.remove(logTask.getTask_id());}CronTask task = new CronTask(new Runnable() {@Overridepublic void run() {//每个计划任务实际需要执行的具体业务逻辑System.out.println("正在执行的任务ID: "+logTask.getTask_id()+" |执行的cron表达式: "+logTask.getExpression());}}, expression);ScheduledFuture<?> future = registrar.getScheduler().schedule(task.getRunnable(), task.getTrigger());cronTasks.put(logTask.getTask_id(), task);scheduledFutures.put(logTask.getTask_id(), future);}}private boolean exists(List<LogTask> tasks, Integer tid){for(LogTask logTask:tasks){if(logTask.getTask_id() == tid){return true;}}return false;}@PreDestroypublic void destroy() {registrar.destroy();}
}
五、定时任务相关实体类(可以根据实际业务场景进行字段添加)
import lombok.Data;@Data
public class LogTask {private int task_id;private String expression;
}
六、进行Controller层代码编写(Service层和Mapper层代码可自己实现)
import cn.sdata.config.ScheduledTask;
import cn.sdata.entity.LogTask;
import cn.sdata.entity.Scheduled;
import cn.sdata.service.ScheduledTaskService;
import lombok.AllArgsConstructor;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.util.ArrayList;
import java.util.List;/*** @author lzw* @create 2022-07-14-9:35* 定时任务相关*/
@RestController
@RequestMapping("cron")
@AllArgsConstructor
public class CronController { private final ScheduledTaskService scheduledTaskService;@GetMapping("cron")public void cron(){//创建一个任务的容器List<LogTask> logTasks = new ArrayList<>();//读取数据库中的任务信息为LogTask字段进行赋值并添加进容器中List<Scheduled> list = scheduledTaskService.findAll();for (Scheduled scheduled : list) {LogTask logTask = new LogTask();logTask.setTask_id(scheduled.getId());logTask.setExpression(scheduled.getTaskCron());logTasks.add(logTask);}//创建一个任务线程池与任务的逻辑连接纽带ScheduledTask scheduledTask = new ScheduledTask();//调用configureTasks()方法传入ScheduledTaskscheduledTask.configureTasks(new ScheduledTaskRegistrar());//调用refresh()方法传入任务数据scheduledTask.refresh(logTasks);}
}
七、启动程序调用cron方法
定时任务正在并发执行
八、修改数据库中的cron数据并再次调用cron方法
当数据库中定时任务信息发生变更时可根据自己的业务场景再次调用refresh()方法
九、删除数据库中的一条cron数据并再次调用cron方法
动态多线程执行定时任务成功,并且极其灵活!
【定时任务】SpringBoot多线程并发动态执行定时任务相关推荐
- java获取mysql数据定时执行_详解SpringBoot 创建定时任务(配合数据库动态执行)...
序言:创建定时任务非常简单,主要有两种创建方式:一.基于注解(@Scheduled) 二.基于接口(SchedulingConfigurer). 前者相信大家都很熟悉,但是实际使用中我们往往想从数据库 ...
- quart动态执行定时任务
今天有个需求,前端可以将定时任务自定义保存到数据库,每天根据查询数据库来执行任务. 其实不用动态也是可以实现,但是.也是想试试动态执行定时任务看看怎么样的. (1)建立一个QuartzManage类 ...
- Springboot定时任务原理及如何动态创建定时任务
一.前言 上周工作遇到了一个需求,同步多个省份销号数据,解绑微信粉丝.分省定时将销号数据放到SFTP服务器上,我需要开发定时任务去解析文件.因为是多省份,服务器.文件名规则.数据规则都不一定,所以要做 ...
- springboot 不停服动态更新定时任务时间(转)
转 https://blog.csdn.net/u012129558/article/details/80834303 Spring框架自3.0版本起,自带了任务调度功能,好比是一个轻量级的Quart ...
- java 多线程 变慢_java多线程并发程序执行慢有什么原因?该怎么解决?
我们在执行java多线程并发程序时有时候会碰到执行特别慢的场景,小伙伴们知道是什么原因导致的吗?它要怎么解决呢?下面小编就为你讲讲. 前提:在某地需要开发一个应用系统,此系统主要功能是能够让一些中小型 ...
- 定时任务(三)动态配置定时任务
第二篇我们主要介绍了Quartz引入Spring框架的基本配置,这一篇直接开始对定时任务进行动态操控 一. 创建相关实体类 (1)定时任务参数 (2)存储TriggerName 的类,主要用来防重 ( ...
- Springboot+多线程+等待获取执行结果
在日常的开发项目过程中,时常会有多线程的使用场景.最近开发的需求中也是如此,只不过这次需要开启多线程去执行,最后要等所有线程结束统一获取结果.所以在此整理一下 在springboot项目中开启异步线程 ...
- boot定时任务开启和关闭 spring_spring-boot 多线程并发定时任务的解决方案
刚刚看了下Spring Boot实现定时任务的文章,感觉还不错.Spring Boot 使用Spring自带的Schedule来实现定时任务变得非常简单和方便.在这里个大家分享下. 开启缓存注解 @S ...
- 【定时任务】Spring Boot 定时执行任务详解,每天定时几点钟执行任务
目录 一.静态:基于注解 二.动态:基于接口 三.多线程定时任务 序言: 使用SpringBoot创建定时任务非常简单,目前主要有以下三种创建方式: 一.基于注解(@Scheduled) 二.基于接口 ...
- SpringBoot使用@Scheduled注解实现定时任务
序言 Spring 3.0 版本之后自带定时任务,提供了@EnableScheduling注解和@Scheduled注解来实现定时任务功能. 使用SpringBoot创建定时任务非常简单,目前主要有以 ...
最新文章
- 腾讯回应博鳌AI同传:系谣言,承认出现失误
- MySQL 高频 100 问
- mysql和php的登录注册界面_php实现注册和登录界面的方法
- PyQt:成功解决Exception quot;unhandled TypeErrorquot; expected str, bytes or os.PathLike object, no
- 网易云以场景化云服务力拓教育行业
- 3. 机器学习中为什么需要梯度下降?梯度下降算法缺点?_浅谈随机梯度下降amp;小批量梯度下降...
- 通过听力写代码?盲人程序员就是这样做的
- MSDN中关于链接字体的解释(非常有用)
- 多校第二场 1004 hdu 5303 Delicious Apples(背包+贪心)
- 对于以太网口作为下一条路由的理解
- 001 lambda的分析
- openGL编程指南第一章
- UE4 UE5学习和资源网站整理
- 非IE内核浏览器支持activex插件
- 马云给阿里的礼物:90多项区块链专利,全球最多
- 词干提取(stemming)和词形还原(lemmatization)
- Go工程管理和业务实践
- linuxi下的做图工具——gnuplot安装
- 【华为OD机试真题 JAVA】叠积木
- 整体大于部分_康托尔集合论:无穷集合中,整体不一定大于部分
热门文章
- Convert Binary Search Tree to Sorted Doubly Linked List
- Rancher Cluster is being upgraded
- 如何把应用程序变成.exe执行文件
- UE4-角色摄像机镜头的设置
- 2008年金融危机的背后原因以及感悟
- 400+条实用C/C++框架、库、工具整理 ,你能想到的都在这里了
- matlab 矩阵增加行,MATLAB 中 如何在矩阵中插入1行
- 【xsy1061】排列 树状数组
- 福大软工1816 · 团队现场编程实战(抽奖系统)
- matlab设置角度和弧度制,matlab 可不可以用角度制不用弧度制?