Java常用三类定时器快速入手指南

文章目录

  • Java常用三类定时器快速入手指南
    • 一、序言
    • 二,Timer相关
      • 1、概念
      • 2、Timer类
      • 3、TimerTask类
      • 4、ScheduleExecutorService接口
    • 三,Scheduled相关
      • 1、配置
        • 1.1 SpringMVC配置
        • 1.2 SpringBoot配置
          • (1)单线程
          • (2)多线程
      • 2、使用方法
        • 2.1 cron表达式
        • 2.2 其他参数
    • 四,Quartz相关
      • 1、概念
      • 2、使用方法
        • 2.1 导入依赖
        • 2.2 实现功能
        • 2.3 示例
      • 3、进阶使用
        • 3.1 存储数据
          • (1)JobDataMap及jobDetail
          • (2)私有属性
        • 3.2 Job并发与持久化
          • (1)并发
          • (2)持久化
        • 3.3 Trigger
          • (1)通用属性
          • (2)SimpleTrigger介绍
          • (3)CronTrigger介绍
      • 4、集群
        • 4.1 步骤一
        • 4.2 步骤二
        • 4.3 步骤三
      • 5、实例代码
        • 5.1 实体entity
        • 5.2 业务service


Java常用三类定时器快速入手指南

一、序言

小豪近来工作有遇到定时任务相关的需求,通常情况下,使用Spring框架自带的Scheduled注解就能满足大部分简单任务的需求,最近遇到的定时任务需求稍显复杂,Scheduled已经有些力不从心了,遂考虑集成第三方定时任务框架Quartz组件,完成业务需求。

本文小豪着重以代码案例的形式呈现,旨在帮助初学者快速入手Java定时器,掌握Java中常用三类定时任务的基本概念及用法。本文大纲如下:

在这里插入图片描述

二,Timer相关

1、概念

Timerjava.util.Timer工具类,java.util包主要使用TimerTimerTask这两个类:

  • Timer直接从Object继承,相当计时器,能够用它来指定某个时间来执行一项任务,或者每隔一定时间间隔反复执行同一个任务。创建一个Timer后,就会生成一个线程在背后运行,来控制任务的执行。
  • TimerTask就是用来实现某项任务的类,它实现了Runnable接口,因此相当于一个线程。

2、Timer类

(1)构造方法

// 创建一个新计时器
Timer()// 创建新计时器,可指定其相关的线程作为守护线程运行
Timer(boolean isDaemon)// 创建新计时器,设置指定名称
Timer(String name)// 创建新计时器,设置指定名称及是否守护线程
Timer(String name, boolean isDaemon)

(2)普通方法

// 安排在指定延迟后执行指定的任务
/* 参数:task - 所要安排的任务delay - 执行任务前的延迟时间,单位是毫秒
*/
void schedule(TimerTask task,long delay)
// 例:程序启动后3秒之后执行
Timer timer=new Timer();timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("定时器执行。。。");}}, 3000);// 安排在指定的时间执行指定的任务。如果此时间已过去,则安排立即执行该任务(参数二:new Date() 代表立刻执行)
void schedule(TimerTask task,Date time)// 安排指定的任务从指定的延迟后开始进行重复的固定延迟执行。以近似固定的时间间隔(由指定的周期分隔)进行后续执行
/* 参数:task - 所要安排的任务delay - 执行任务前的延迟时间,单位是毫秒period - 执行各后续任务之间的时间间隔,单位是毫秒
*/
void schedule(TimerTask task,long delay,long period)// 安排指定的任务在指定的时间开始进行重复的固定延迟执行。以近似固定的时间间隔(由指定的周期分隔)进行后续执行
void schedule(TimerTask task,Date firstTime,long period)// 安排指定的任务在指定的延迟后开始进行重复的固定速率执行。以近似固定的时间间隔(由指定的周期分隔)进行后续执行
void scheduleAtFixedRate(TimerTask task,long delay,long period)// 安排指定的任务在指定的时间开始进行重复的固定速率执行。以近似固定的时间间隔(由指定的周期分隔)进行后续执行
void scheduleAtFixedRate(TimerTask task,Date firstTime,long period)// 终止此计时器,丢弃所有当前已安排的任务
void cancel()// 从此计时器的任务队列中移除所有已取消的任务
int purge()

3、TimerTask类

(1)构造方法

// 创建新的计时器任务
TimerTask()

(2)普通方法

// 取消此计时器任务
boolean cancel()// 返回此任务最近实际执行的安排执行时间
long scheduledExecutionTime()// 此计时器任务要执行的操作(接口Runnable中的run)
void run()

4、ScheduleExecutorService接口

(1)概念

ScheduledExecutorService线程池实现循环或延迟任务。

ScheduledExecutorServiceTimer 的区别:

  1. Timer的内部只有一个线程,如果有多个任务的话就会顺序执行,会导致延迟时间和循环时间出现问题
  2. ScheduledExecutorService是线程池,不会出现此问题,在对延迟任务和循环任务要求严格的时候,可使用ScheduledExecutorService

(2)使用方法

// 1.创建ScheduledExecutorService的实例(参数指定最大线程数量)
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);
// 2.调用方法
scheduledExecutorService.scheduleAtFixedRate(xxx...);

(3)普通方法

// 在给定的延迟之后创建并执行启用的一次性操作。
/*command - 命令要执行的任务delay - 从现在开始延迟执行的时间unit - 延迟参数的时间单位
*/
ScheduledFuture<?> schedule(Runnable command,long delay,TimeUnit unit);ScheduledFuture<V> schedule(Callable<V> callable,long delay, TimeUnit unit);// 在给定的初始延迟之后创建并执行启用的周期性操作
/*command - 命令要执行的任务initialDelay - 延迟第一次执行的时间period - 连续执行之间的时间间隔unit - initialDelay和period参数的时间单位
*/
ScheduledFuture<?> scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit);// 在给定的初始延迟之后创建并执行先启用的周期性操作
ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnit unit);

三,Scheduled相关

1、配置

1.1 SpringMVC配置
<!--1.在xml里加入task的命名空间-->
xmlns:task="http://www.springframework.org/schema/task" 
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.1.xsd<!--2.启用注解驱动的定时任务-->
<task:annotation-driven scheduler="myScheduler"/><!--3.配置定时任务的线程池-->
<task:scheduler id="myScheduler" pool-size="5"/>
1.2 SpringBoot配置
(1)单线程

在启动类添加@EnableScheduling注解即可

(2)多线程
@Configuration
@EnableScheduling
public class SchedulingConfig implements SchedulingConfigurer {@Overridepublic void configureTasks(ScheduledTaskRegistrar taskRegistrar) {taskRegistrar.setScheduler(taskExecutor());}@Bean(destroyMethod="shutdown")public Executor taskExecutor() {return Executors.newScheduledThreadPool(5 ,new ThreadFactory() {private final AtomicLong counter = new AtomicLong();@Overridepublic Thread newThread(Runnable r) {Thread thread = new Thread(r);thread.setName("scheduler-" + counter.incrementAndGet());return thread;}	});}	
}

2、使用方法

@Scheduled注解使用的方法必须是在@Component注解下的类

2.1 cron表达式
<--在方法上使用@Scheduled,并配置对应参数即可-->
使用cron表达式的方法,在项目首次启动后不会直接运行,而是等到执行周期才会执行( 0/2 * * * * ? 表示每2秒执行任务)<--在线cron生成地址-->
https://www.bejson.com/othertools/cron/
2.2 其他参数

在这里插入图片描述

// 使用fixedRate/fixedDelay方式的定时器方法,在项目启动成功后会马上开始执行一次,再按照时间周期执行
// 例:@Scheduled(fixedDelay = 1000 * 5)fixedRate/fixedDelay区别:
fixedRate是配置上一次任务执行开始到下一次执行开始的间隔时间,不会等待上一次任务执行完成就会调度下一次任务,将其放入等待队列中
fixedDelay是配置的上一次任务执行结束到下一次执行开始的间隔时间,也就是说会等待上一次任务执行结束后,延迟间隔时间,再执行下一次任务

四,Quartz相关

1、概念

Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,完全由Java开发,可以用来执行定时任务,类似于java.util.Timer。相较Timer, Quartz强大许多,具备分布式、持久性作业、调度任务管理能力。

Quartz的基本组成部分:

  • 调度器:Scheduler
  • 任务:JobDetail
  • 触发器:Trigger,包括SimpleTriggerCronTrigger

2、使用方法

2.1 导入依赖
<!-- springboot -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
或者:
<!-- springmvc -->
<dependency> <groupId>org.quartz-scheduler</groupId><artifactId>quartz</artifactId>
</dependency>
<dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz-jobs</artifactId>
</dependency>
2.2 实现功能

(1)定义实现定时功能的接口,称之为Task(或Job

在这里插入图片描述

(2)实现触发任务去执行的触发器,触发器Trigger最基本的功能是指定Job的执行时间,执行间隔,运行次数等

在这里插入图片描述

(3)使用Schedule,将JobTrigger两者结合起来,来负责功能的实现

在这里插入图片描述

2.3 示例

(1)新建一个能够打印任意内容的Job

public class PrintWordsJob implements Job {// 此类实现Job接口,复写execute()方法@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {System.out.println("定时器执行啦。。。"+new Date());}
}

(2)创建Schedule,执行任务

public class MyScheduler {public static void main(String[] args) throws SchedulerException {// 1.创建调度器SchedulerSchedulerFactory schedulerFactory = new StdSchedulerFactory();Scheduler scheduler = schedulerFactory.getScheduler();// 2.创建JobDetail实例,并与PrintWordsJob自定义类绑定(Job执行内容)JobDetail jobDetail = JobBuilder.newJob(PrintWordsJob.class).withIdentity("job1", "group1").build();// 3.构建Trigger实例,每隔3s执行一次// 使用SimpleScheduleBuilder或者CronScheduleBuilderTrigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "triggerGroup1").startNow()//立即生效.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(3)//每隔3s执行一次.repeatForever()).build();//一直执行// 4.注册任务和定时器scheduler.scheduleJob(jobDetail, trigger);System.out.println("--------scheduler start! ------------");// 5.启动调度器scheduler.start();}}

3、进阶使用

3.1 存储数据
(1)JobDataMap及jobDetail
  • JobDataMapJava Map接口的一个实现,额外增加了一些便于存取基本类型的数据的方法,用于保存任务实例的状态信息
  • jobDetail:包含job的各种属性设置,以及用于存储job实例状态信息的JobDataMap

a.构建方式

//方式一:直接在构建JobDetail时,通过JobBuilder的usingJobData方法将数据放入JobDataMap中// 构建JobDetail实例
JobDetail job = JobBuilder.newJob(HelloJob.class).withIdentity("helloJob", "hello")//给job命名并分组.usingJobData("jobdd", "hello job")//通过JobBuilder的usingJobData方法给JobDataMap中存数据.build();
//方式二:构建JobDataMap,然后存入JobDetail中。或者从JobDetail中获取往里面put数据// 构建JobDetail实例
JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put("jobcc", "哈哈");
JobDetail job = JobBuilder.newJob(HelloJob.class).withIdentity("helloJob", "hello")//给job命名并分组.usingJobData("jobdd", "hello job")//通过JobBuilder的usingJobData方法向JobDataMap中存数据.usingJobData(jobDataMap).build();

b.取数据方法

// 在job的执行过程中,可以从JobDataMap中取出数据// JobDetail的key由name和group组成
JobKey jobKey = jobExecutionContext.getJobDetail().getKey();
// Trigger的key由name和group组成
TriggerKey triggerKey = jobExecutionContext.getTrigger().getKey();
String bob = jobExecutionContext.getJobDetail().getJobDataMap().getString("jobdd");
String bob = jobExecutionContext.getJobDetail().getJobDataMap().getString("jobcc");
(2)私有属性

自定义私有属性,job被实例化的时会自动调用其set方法

public class HelloJob implements Job {//定义私有属性,会自动封装给jobprivate String jobcc;private String jobdd;private String jobaa;public void setJobcc(String jobcc) {this.jobcc = jobcc;}public void setJobdd(String jobdd) {this.jobdd = jobdd;}public void setJobaa(String jobaa) {this.jobaa = jobaa;}@Overridepublic void execute(JobExecutionContext context) throws JobExecutionException {System.err.println(context.getJobDetail().getKey());// JobDetail的key由name和group组成System.err.println(context.getTrigger().getKey());// Trigger的key由name和group组成System.err.println(jobcc);System.err.println(jobdd);System.err.println(jobaa);System.err.println("hello,quartz");}}
3.2 Job并发与持久化

仅在job类上加入部分注解,即可实现Job的并发与持久化。

(1)并发
@DisallowConcurrentExecution:将该注解加到job类上,告诉Quartz不要并发地执行同一个job定义(这里指特定的job类)的多个实例。
(2)持久化
@PersistJobDataAfterExecution:将该注解加在job类上,告诉Quartz在成功执行了job类的execute方法后(没有发生任何异常),更新JobDetail中JobDataMap的数据,使得该job(即JobDetail)在下一次执行的时候,JobDataMap中是更新后的数据,而不是更新前的旧数据。若使用@PersistJobDataAfterExecution注解,同时建议使用@DisallowConcurrentExecution注解
3.3 Trigger

TriggerQuartz框架中的核心接口,其最重要的两个实现类是CronTriggerImplSimpleTriggerImpl

(1)通用属性
  • JobKey:表示与该Trigger绑定的Job实例的标识,触发器被触发时,该指定的Job实例会被执行

  • StartTime:表示触发器的时间表首次被触发的时间,Java.util.Date类型

  • EndTime:指定触发器不再被触发的时间,Java.util.Date类型

(2)SimpleTrigger介绍

在一个指定时间段内执行一次作业任务或是在指定的时间间隔内多次执行作业任务

// 实例:距离当前时间4秒钟之后首次执行任务,6秒后停止,每隔2秒执行,执行3次
// 创建一个SimpleTrigger实例,定义该Job4秒后执行,并且每隔两秒钟重复执行一次,6秒后停止
SimpleTrigger trigger=(SimpleTrigger)TriggerBuilder.newTrigger().withIdentity("myTrigger", "group1")//定义name和group.startAt(date)//设置开始时间.endAt(endDate)//设置结束时间 .withSchedule(SimpleScheduleBuilder.simpleSchedule() //使用SimpleTrigger .withIntervalInSeconds(2)//每隔两秒执行一次 .withRepeatCount(3))//重复执行三次 .build();
(3)CronTrigger介绍

基于日历的作业调度器,而不是像SimpleTrigger那样精确指定间隔时间,SimpleTrigger能够实现的,CronTrigger都能够实现,基本普遍都用CronTrigger

// 创建一个CronTrigger实例
CronTrigger trigger=(CronTrigger)TriggerBuilder.newTrigger().withIdentity("myTrigger", "group1")//定义name/group.withSchedule(CronScheduleBuilder.cronSchedule("0 5 21 * * ? *"))//填写cron表达式.build();

4、集群

4.1 步骤一

(1)下载quartz表

http://www.quartz-scheduler.org/downloads/

(2)表功能说明

在这里插入图片描述

(3)导入配置文件(quartz.properties)

# 配置JobStore,JobDataMaps是否都为String类型,默认false
org.quartz.jobStore.useProperties=false# 表的前缀,默认QRTZ_
org.quartz.jobStore.tablePrefix = QRTZ_# 是否加入集群
org.quartz.jobStore.isClustered = true# 调度实例失效的检查时间间隔 ms
org.quartz.jobStore.clusterCheckinInterval = 5000# 当设置为“true”时,此属性告诉Quartz 在非托管JDBC连接上调用setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED)。
org.quartz.jobStore.txIsolationLevelReadCommitted = true# 数据保存方式为数据库持久化
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX# 数据库代理类,一般org.quartz.impl.jdbcjobstore.StdJDBCDelegate可以满足大部分数据库
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate# Scheduler 调度器属性配置
# 调度标识名 集群中每一个实例都必须使用相同的名称
org.quartz.scheduler.instanceName = ClusterQuartz
# ID设置为自动获取 每一个必须不同
org.quartz.scheduler.instanceId= AUTO# 配置ThreadPool
# 线程池的实现类(一般使用SimpleThreadPool即可满足几乎所有用户的需求)
org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool# 指定线程数,一般设置为1-100直接的整数,根据系统资源配置
org.quartz.threadPool.threadCount = 10# 设置线程的优先级(可以是Thread.MIN_PRIORITY(即1)和Thread.MAX_PRIORITY(这是10)之间的任何int 。默认值为Thread.NORM_PRIORITY(5)。)
org.quartz.threadPool.threadPriority = 5

(4)配置数据源

spring.datasource.url=jdbc:mysql://localhost:3306/xiaohao?characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=admin
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.max-active=1000
spring.datasource.max-idle=20
spring.datasource.min-idle=5
spring.datasource.initial-size=10
4.2 步骤二

(1)QuartzConfigure配置类

@Configuration
public class SchedulerConfig {/*** 配置文件路径*/private static final String QUARTZ_CONFIG = "/quartz.properties";/*** 注入数据源*/@Autowiredprivate DataSource dataSource;/*** 通过SchedulerFactoryBean获取Scheduler的实例*/@Beanpublic Scheduler scheduler() throws IOException {return schedulerFactoryBean().getScheduler();}/*** 配置SchedulerFactory*/@Beanpublic SchedulerFactoryBean schedulerFactoryBean() throws IOException {SchedulerFactoryBean factory = new SchedulerFactoryBean();factory.setSchedulerName("cluster_scheduler");factory.setDataSource(dataSource);//将spring上下文放入quartz中, 用于在job执行时获取注入beanfactory.setApplicationContextSchedulerContextKey("application");factory.setQuartzProperties(quartzProperties());factory.setTaskExecutor(schedulerThreadPool());//延时3秒启动factory.setStartupDelay(3);return factory;}/*** 从quartz.properties文件中读取Quartz配置属性*/@Beanpublic Properties quartzProperties() throws IOException {PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();propertiesFactoryBean.setLocation(new ClassPathResource(QUARTZ_CONFIG));propertiesFactoryBean.afterPropertiesSet();return propertiesFactoryBean.getObject();}/*** 自定义线程池*/@Beanpublic Executor schedulerThreadPool(){ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(Runtime.getRuntime().availableProcessors());executor.setMaxPoolSize(Runtime.getRuntime().availableProcessors());executor.setQueueCapacity(Runtime.getRuntime().availableProcessors());return executor;}
}

(2)QuartzJob定时任务类

// QuartzJobBean抽象类默认实现Job接口,并对工厂进行了一些自动化配置
// 及时更新JobDetail中JobDataMap的数据
@PersistJobDataAfterExecution
// 标记于实现Job的类上,代表不允许并发执行
@DisallowConcurrentExecution
public class QuartzJob extends QuartzJobBean {/*** Quartz Job真正的执行逻辑*/@Overrideprotected void executeInternal(JobExecutionContext context) throws JobExecutionException {try {System.out.println(context.getScheduler().getSchedulerInstanceId());System.out.println("定时器执行啦。。。");} catch (Exception e) {e.printStackTrace();}}
}
4.3 步骤三

(1)定义任务

@Controller
public class MyTask {@Autowiredprivate Scheduler scheduler;@RequestMapping("/setScheduler")@ResponseBodypublic String setScheduler() throws SchedulerException {// 1.创建JobDetail实例,并与QuartzJob自定义类绑定(Job执行内容)JobDetail jobDetail = JobBuilder.newJob(QuartzJob.class).withIdentity("job1", "group1").build();// 2.构建Trigger实例,每隔3s执行一次// 使用SimpleScheduleBuilder或者CronScheduleBuilderTrigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "triggerGroup1").startNow()//立即生效.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(3)//每隔3s执行一次.repeatForever()).build();//一直执行// 3.注册任务和定时器,交给scheduler调度scheduler.scheduleJob(jobDetail, trigger);return "hello,quartz";}
}

5、实例代码

5.1 实体entity
@Data
public class JobAndTrigger {/*** 任务名称(*)*/private String jobName;/*** 任务所在组(*)*/private String jobGroup;/*** 任务类名(*)* 例:"com.example.demo.task.QuartzJob"*/private String jobClassName;/*** 触发器名称*/private String triggerName;/*** 触发器所在组*/private String triggerGroup;/*** cron表达式(*)*/private String cronExpression;/*** 时区*/private String timeZoneId;/*** 任务描述(*)*/private String description;/*** 状态*/private String triggerState;
}
5.2 业务service
@Service
@Slf4j
public class JobService {@Autowiredprivate Scheduler scheduler;/*** 添加一个定时任务** @param jobAndTrigger*/public void addCronJob(JobAndTrigger jobAndTrigger) throws SchedulerException {try {JobKey jobKey = JobKey.jobKey(jobAndTrigger.getJobName(), jobAndTrigger.getJobGroup());JobDetail jobDetail = scheduler.getJobDetail(jobKey);if (jobDetail != null) {log.error("job:" + jobAndTrigger.getJobName() + " 已存在");} else {// 创建JobDetail实例,并与QuartzJob自定义类绑定(Job执行内容)jobDetail = JobBuilder.newJob((Class<Job>) Class.forName(jobAndTrigger.getJobClassName())).withIdentity(jobAndTrigger.getJobName(), jobAndTrigger.getJobGroup()).withDescription(jobAndTrigger.getDescription()).build();// 用JopDataMap来传递数据jobDetail.getJobDataMap().put("taskData", "定时任务传递数据");// 表达式调度构建器,首先校验表达式格式if (!CronExpression.isValidExpression(jobAndTrigger.getCronExpression())) {log.error("cron表达式规则不正确");}CronScheduleBuilder cron = CronScheduleBuilder.cronSchedule(jobAndTrigger.getCronExpression());// 根据cronExpression表达式构建新的triggerTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobAndTrigger.getJobName() + "_trigger", jobAndTrigger.getJobGroup() + "_trigger").withSchedule(cron).withDescription(jobAndTrigger.getDescription()).build();// 注册任务和定时器,交给scheduler调度scheduler.scheduleJob(jobDetail, trigger);}} catch (Exception e) {log.error("任务创建失败:", e);}}/*** 暂停任务** @param jobName* @param jobGroup*/public void pauseJob(String jobName, String jobGroup) throws SchedulerException {try {TriggerKey triggerKey = TriggerKey.triggerKey(jobName + "_trigger", jobGroup + "_trigger");scheduler.pauseTrigger(triggerKey);} catch (SchedulerException e) {log.error("定时任务暂停失败:", e);}}/*** 恢复任务** @param jobName* @param jobGroup*/public void resumeJob(String jobName, String jobGroup) throws SchedulerException {try {TriggerKey triggerKey = TriggerKey.triggerKey(jobName + "_trigger", jobGroup + "_trigger");scheduler.resumeTrigger(triggerKey);} catch (SchedulerException e) {log.error("定时任务恢复失败:", e);}}/*** 修改任务表达式并重新调度** @param jobAndTrigger*/public void rescheduleJob(JobAndTrigger jobAndTrigger) throws SchedulerException {try {TriggerKey triggerKey = TriggerKey.triggerKey(jobAndTrigger.getJobName() + "_trigger", jobAndTrigger.getJobGroup() + "_trigger");// 表达式调度构建器CronScheduleBuilder cron = CronScheduleBuilder.cronSchedule(jobAndTrigger.getCronExpression());CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);String oldCron = trigger.getCronExpression();if (oldCron.isEmpty() || !oldCron.equals(jobAndTrigger.getCronExpression())) {// 表达式调度构建器,首先校验表达式格式if (!CronExpression.isValidExpression(jobAndTrigger.getCronExpression())) {log.error("cron表达式规则不正确");}// 按新的cronExpression表达式重新构建triggertrigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(cron).build();// 按新的trigger重新设置job执行scheduler.rescheduleJob(triggerKey, trigger);}} catch (SchedulerException e) {log.error("定时任务修改失败:", e);}}/*** 删除job** @param jobName* @param jobGroup*/public void deleteJob(String jobName, String jobGroup) throws SchedulerException {try {JobKey jobKey = JobKey.jobKey(jobName, jobGroup);scheduler.deleteJob(jobKey);} catch (SchedulerException e) {log.error("定时任务删除失败:", e);}}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/435891.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

cpp,git,unity学习

c#中的? 1. 空值类型&#xff08;Nullable Types&#xff09; ? 可以用于值类型&#xff08;例如 int、bool 等&#xff09;&#xff0c;使它们可以接受 null。通常&#xff0c;值类型不能为 null&#xff0c;但是通过 ? 可以表示它们是可空的。 int? number null; // …

桥接(桥梁)模式

简介 桥接模式&#xff08;Bridge Pattern&#xff09;又叫作桥梁模式、接口&#xff08;Interface&#xff09;模式或柄体&#xff08;Handle and Body&#xff09;模式&#xff0c;指将抽象部分与具体实现部分分离&#xff0c;使它们都可以独立地变化&#xff0c;属于结构型…

【AAOS】CarService -- Android汽车服务

概述 Android Automative OS理解为Android OS + Android Automative Service,而CarService就是提供汽车相关功能的最主要模块。 CarService与Android OS的关系:CarService运行于独立的进程中,其作为原有Android服务的补充,在汽车设备上运行。CarService在整体车载通信中起…

JAVA线程基础二——锁的概述之乐观锁与悲观锁

乐观锁与悲观锁 乐观锁和悲观锁是在数据库中引入的名词,但是在并发包锁里面也引入了类似的思想&#xff0c;所以这里还是有必要讲解下。 悲观锁指对数据被外界修改持保守态度&#xff0c;认为数据很容易就会被其他线程修改&#xff0c;所以在数据被处理前先对数据进行加锁&…

python 如何引用变量

在字符串中引入变量有三种方法&#xff1a; 1、 连字符 name zhangsan print(my name is name) 结果为 my name is zhangsan 2、% 字符 name zhangsan age 25 price 4500.225 print(my name is %s%(name)) print(i am %d%(age) years old) print(my price is %f%(pric…

项目管理专业资质认证ICB 3中关于项目经理素质的标准

项目管理专业资质认证ICB 3中关于项目经理素质的标准&#xff0c;的确很全面&#xff0c;下面摘录之&#xff1a;

15年408计算机网络

第一题&#xff1a; 解析&#xff1a; 接收方使用POP3向邮件服务器读取邮件&#xff0c;使用的TCP连接&#xff0c;TCP向上层提供的是面向连接的&#xff0c;可靠的数据传输服务。 第二题&#xff1a; 解析&#xff1a;物理层-不归零编码和曼彻斯特编码 编码1&#xff1a;电平在…

LabVIEW项目编码器选择

在LabVIEW项目中&#xff0c;选择增量式&#xff08;Incremental Encoder&#xff09;和绝对式&#xff08;Absolute Encoder&#xff09;编码器取决于项目的具体需求。增量式编码器和绝对式编码器在工作原理、应用场景、精度和成本等方面存在显著差异。以下从多方面详细阐述两…

又一年国庆至,“打工人”在欢呼,OTA们在雀跃

国庆“黄金周”倒计时最后一天&#xff0c;旅游出行即将迎来新一轮高峰。 安信国际指出&#xff0c;国庆期间&#xff0c;出游人次的增长确定性高于人均消费的增长。预计国内旅游收入7,000-7,500亿元&#xff0c;较2019年同期增8%-15%&#xff1b;预计国内旅游人次8.5-9.0亿人…

今日指数项目A股大盘数据采集

1、A股大盘数据采集 1.1 A股大盘数据采集准备 1.1.1 配置ID生成器bean A股大盘数据采集入库时&#xff0c;主键ID保证唯一&#xff0c;所以在stock_job工程配置ID生成器&#xff1a; Configuration public class CommonConfig {/*** 配置基于雪花算法生成全局唯一id* 参与…

springboot+大数据+基于协同过滤算法的校园食堂订餐系统【内含源码+文档+部署教程】

博主介绍&#xff1a;✌全网粉丝10W,前互联网大厂软件研发、集结硕博英豪成立工作室。专注于计算机相关专业毕业设计项目实战6年之久&#xff0c;选择我们就是选择放心、选择安心毕业✌ &#x1f345;由于篇幅限制&#xff0c;想要获取完整文章或者源码&#xff0c;或者代做&am…

Git常用方法——详解

一、下载安装git git官网&#xff1a; Git - Downloads (git-scm.com) 下载安装Git&#xff08;超详细超简单&#xff09;_git下载-CSDN博客 二、克隆下载至本地 1、复制HTTPS链接 在gitee或者gitLab或者gitHub上复制HTTPS链接 2、打开Open Git Bash here 在本地想要新建文…

闯关训练一:Linux基础

闯关任务&#xff1a;完成SSH连接与端口映射并运行hello_world.py 1.创建开发机 2.SSH连接 3. VS-Code 连接 选择 Linux 平台 &#xff0c;输入密码 &#xff0c;选择进入文件夹 4.端口映射 按照下文安装Docs pip install gradio 运行server.py import gradio as grdef …

工业制造场景中的设备管理深度解析

在工业制造的广阔领域中&#xff0c;设备管理涵盖多个关键方面&#xff0c;对企业的高效生产和稳定运营起着举足轻重的作用。 一、设备运行管理 1.设备状态监测 实时监控设备的运行状态是确保生产顺利进行的重要环节。通过传感器和数据采集系统等先进技术&#xff0c;获取设备…

新书速览|Stable Diffusion-ComfyUI AI绘画工作流解析

《Stable Diffusion-ComfyUI AI绘画工作流解析》 本书内容 《Stable Diffusion-ComfyUI AI绘画工作流解析》从零开始&#xff0c;详尽系统地讲解从本地部署ComfyUI、下载安装自定义节点&#xff0c;到搭建各种工作流程的全过程。同时&#xff0c;辅以3D形象转绘、艺术二维码和证…

思科dhcp的配置

以路由器为例 让pc3 自动获取ip地址并获取的网段为172.16.4.100-172.16.4.200 配置如下&#xff1a; R1(config)#interface GigabitEthernet0/2 R1(config)#ip address 172.16.4.254 255.255.255.0 R1(config)# no shutdown R1(config)#ip dhcp pool 4_pool //创建dhcp地址池…

【原创】java+swing+mysql企业招聘管理系统设计与实现

个人主页&#xff1a;程序员杨工 个人简介&#xff1a;从事软件开发多年&#xff0c;前后端均有涉猎&#xff0c;具有丰富的开发经验 博客内容&#xff1a;全栈开发&#xff0c;分享Java、Python、Php、小程序、前后端、数据库经验和实战 文末有本人名片&#xff0c;希望和大家…

【设计模式-模板】

定义 模板方法模式是一种行为设计模式&#xff0c;它在一个方法中定义了一个算法的骨架&#xff0c;并将一些步骤延迟到子类中实现。通过这种方式&#xff0c;模板方法允许子类在不改变算法结构的情况下重新定义算法中的某些特定步骤。 UML图 组成角色 AbstractClass&#x…

【DP解密多重背包问题】:优化策略与实现

文章目录 什么是多重背包问题&#xff1f;多重背包问题的数学模型 例题多重背包问题Ⅰ多重背包问题Ⅱ 总结 什么是多重背包问题&#xff1f; 多重背包问题是一个经典的组合优化问题。与标准背包问题不同&#xff0c;在多重背包问题中&#xff0c;每种物品可以选择多个&#xf…

基于php的律所管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏&#xff1a;Java精选实战项目…