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

文章目录


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

一、序言

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

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

二,Timer相关

1、概念

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

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

2、Timer类

(1)构造方法

java 复制代码
// 创建一个新计时器
Timer()

// 创建新计时器,可指定其相关的线程作为守护线程运行
Timer(boolean isDaemon)

// 创建新计时器,设置指定名称
Timer(String name)

// 创建新计时器,设置指定名称及是否守护线程
Timer(String name, boolean isDaemon)

(2)普通方法

java 复制代码
// 安排在指定延迟后执行指定的任务
/* 参数:
 task - 所要安排的任务
 delay - 执行任务前的延迟时间,单位是毫秒
*/
void schedule(TimerTask task,long delay)
// 例:程序启动后3秒之后执行
Timer timer=new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public 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)构造方法

java 复制代码
// 创建新的计时器任务
TimerTask()

(2)普通方法

java 复制代码
// 取消此计时器任务
boolean cancel()

// 返回此任务最近实际执行的安排执行时间
long scheduledExecutionTime()

// 此计时器任务要执行的操作(接口Runnable中的run)
void run()

4、ScheduleExecutorService接口

(1)概念

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

ScheduledExecutorServiceTimer 的区别:

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

(2)使用方法

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

(3)普通方法

java 复制代码
// 在给定的延迟之后创建并执行启用的一次性操作。
/*
 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配置
xml 复制代码
<!--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)多线程
java 复制代码
@Configuration
@EnableScheduling
public class SchedulingConfig implements SchedulingConfigurer {
 
	@Override
	public 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();
			
			@Override
			public Thread newThread(Runnable r) {
				Thread thread = new Thread(r);
				thread.setName("scheduler-" + counter.incrementAndGet());
				return thread;
			}	
		});
    }	
}

2、使用方法

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

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

java 复制代码
public class PrintWordsJob implements Job {

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

(2)创建Schedule,执行任务

java 复制代码
public class MyScheduler {

    public static void main(String[] args) throws SchedulerException {
        // 1.创建调度器Scheduler
        SchedulerFactory 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或者CronScheduleBuilder
        Trigger 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.构建方式

java 复制代码
//方式一:直接在构建JobDetail时,通过JobBuilder的usingJobData方法将数据放入JobDataMap中

// 构建JobDetail实例
JobDetail job = JobBuilder.newJob(HelloJob.class)
	.withIdentity("helloJob", "hello")//给job命名并分组
	.usingJobData("jobdd", "hello job")//通过JobBuilder的usingJobData方法给JobDataMap中存数据
	.build();
java 复制代码
//方式二:构建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.取数据方法

java 复制代码
// 在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方法

java 复制代码
public class HelloJob implements Job {

    //定义私有属性,会自动封装给job
	private 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;
	}

	@Override
	public 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介绍

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

java 复制代码
// 实例:距离当前时间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

java 复制代码
// 创建一个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)

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)配置数据源

properties 复制代码
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配置类

java 复制代码
@Configuration
public class SchedulerConfig {

    /**
     * 配置文件路径
     */
    private static final String QUARTZ_CONFIG = "/quartz.properties";

    /**
     * 注入数据源
     */
    @Autowired
    private DataSource dataSource;

    /**
     * 通过SchedulerFactoryBean获取Scheduler的实例
     */
    @Bean
    public Scheduler scheduler() throws IOException {
        return schedulerFactoryBean().getScheduler();
    }

    /**
     * 配置SchedulerFactory
     */
    @Bean
    public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        factory.setSchedulerName("cluster_scheduler");
        factory.setDataSource(dataSource);
        //将spring上下文放入quartz中, 用于在job执行时获取注入bean
        factory.setApplicationContextSchedulerContextKey("application");
        factory.setQuartzProperties(quartzProperties());
        factory.setTaskExecutor(schedulerThreadPool());
        //延时3秒启动
        factory.setStartupDelay(3);
        return factory;

    }

    /**
     * 从quartz.properties文件中读取Quartz配置属性
     */
    @Bean
    public Properties quartzProperties() throws IOException {
        PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
        propertiesFactoryBean.setLocation(new ClassPathResource(QUARTZ_CONFIG));
        propertiesFactoryBean.afterPropertiesSet();
        return propertiesFactoryBean.getObject();
    }

    /**
     * 自定义线程池
     */
    @Bean
    public 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定时任务类

java 复制代码
// QuartzJobBean抽象类默认实现Job接口,并对工厂进行了一些自动化配置
// 及时更新JobDetail中JobDataMap的数据
@PersistJobDataAfterExecution
// 标记于实现Job的类上,代表不允许并发执行
@DisallowConcurrentExecution
public class QuartzJob extends QuartzJobBean {

    /**
     * Quartz Job真正的执行逻辑
     */
    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        try {
            System.out.println(context.getScheduler().getSchedulerInstanceId());
            System.out.println("定时器执行啦。。。");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
4.3 步骤三

(1)定义任务

java 复制代码
@Controller
public class MyTask {

    @Autowired
    private Scheduler scheduler;

    @RequestMapping("/setScheduler")
    @ResponseBody
    public String setScheduler() throws SchedulerException {

        // 1.创建JobDetail实例,并与QuartzJob自定义类绑定(Job执行内容)
        JobDetail jobDetail = JobBuilder.newJob(QuartzJob.class)
                .withIdentity("job1", "group1")
                .build();
        // 2.构建Trigger实例,每隔3s执行一次
        // 使用SimpleScheduleBuilder或者CronScheduleBuilder
        Trigger 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
java 复制代码
@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
java 复制代码
@Service
@Slf4j
public class JobService {

    @Autowired
    private 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表达式构建新的trigger
                Trigger 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表达式重新构建trigger
                trigger = 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);
        }
    }

}
相关推荐
2401_8574396925 分钟前
SpringBoot框架下体育馆管理系统的构建
java·spring boot·spring
Black—slience26 分钟前
LeetCode2207解题思路
java·算法·leetcode·动态规划
以全速前进32 分钟前
[2024年]最新VMware Workstation虚拟机下载 带链接
java·软件工程
paopaokaka_luck34 分钟前
基于Spring Boot+Vue的减肥健康管理系统设计和实现【原创】(BMI算法,协同过滤算法、图形化分析)
java·vue.js·spring boot·后端
@nastyboy1 小时前
数据结构:链表算法题
c语言·开发语言·数据结构·算法
百炼成神 LV@菜哥2 小时前
记HttpURLConnection下载图片
java·开发语言·后端
iknow1813 小时前
【前端安全】js逆向之微信公众号登录密码
开发语言·前端·javascript
面包会有的,牛奶也会有的。3 小时前
python测试开发---前后端交互Axios
开发语言·前端·vue.js·交互
高高要努力3 小时前
SpringBoot-全局处理异常,时间格式,跨域,拦截器,监听器
java·spring boot·spring
爱数学的程序猿3 小时前
【C++篇】启航——初识C++(下篇)
开发语言·c++