HOME> 装备百科> 一图理解quartz任务调度及注意事项

一图理解quartz任务调度及注意事项

装备百科 2025-10-08 19:07:43
1、单机任务调度,任务可能会重叠并发执行。 如示例:每隔10秒执行此任务,但是任务执行耗时20s 执行结果(任务重叠执行): 解决:单机可...

1、单机任务调度,任务可能会重叠并发执行。

如示例:每隔10秒执行此任务,但是任务执行耗时20s

执行结果(任务重叠执行):

解决:单机可加注解DisallowConcurrentExecution解决,集群环境必须靠分布式如quartz集群方案解决,如果保证不了任务的重叠执行,可以用分布式锁或任务执行幂等性来保证。

示例:使用注解DisallowConcurrentExecution解决效果:

执行结果:

2、使用注解DisallowConcurrentExecution来解决任务重叠问题,可能由于任务执行时间长,导致任务调度不准确。

示例:

执行结果(任务调度周期与耗时相关,不再准确---每隔10s执行,耗时20s):

如果运行任务重叠执行,则(任务调度周期为准-每隔10s执行):

产生1、2现象的原因在于获取可被调度的任务时(默认内存存储任务job及调度信息):

代码语言:javascript代码运行次数:0运行复制org.quartz.simpl.RAMJobStore#acquireNextTriggers当获取任务的触发器时,同时也会删除其存储信息:

在任务被真正调度之前,根据是否可以重叠执行,如果可以重叠执行,则重新把触发器添加存储起来,下次任务调度轮询可以被再次调度:

代码语言:javascript代码运行次数:0运行复制org.quartz.simpl.RAMJobStore#triggersFired当任务被执行完时,不能重叠执行的任务也会被重新存储起来,下次任务调度轮询可以被再次调度:

代码语言:javascript代码运行次数:0运行复制org.quartz.simpl.RAMJobStore#triggeredJobComplete3、任务会因为任务线程池没有空闲线程执行,导致调度线程等待,任务不会再被调度。

任务调度线程获取的任务会交给工作线程池去调度,默认是固定大小的线程池SimpleThreadPool,如果线程池没有空闲线程执行任务,则调度线程会一直等待:

代码语言:javascript代码运行次数:0运行复制org.quartz.core.QuartzSchedulerThread#run代码语言:javascript代码运行次数:0运行复制org.quartz.simpl.SimpleThreadPool#blockForAvailableThreads实现:

4、如果任务需要停止继续被调度,可以抛出异常JobExecutionException,设置信息:

根据异常信息转换为CompletedExecutionInstruction:

根据CompletedExecutionInstruction判断任务是否能被继续调度:

代码语言:javascript代码运行次数:0运行复制org.quartz.simpl.RAMJobStore#triggeredJobComplete附:

代码语言:javascript代码运行次数:0运行复制package com.renzhikeji.demo;

import org.quartz.*;

import org.quartz.impl.StdSchedulerFactory;

import java.util.concurrent.TimeUnit;

public class QuartzDemo {

public static void main(String[] args) throws SchedulerException, InterruptedException {

//创建调度器

Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

//创建触发器

Trigger trigger = TriggerBuilder.newTrigger().withSchedule(CronScheduleBuilder.cronSchedule("0/10 * * * * ?"))

.build();

//定义一个job

JobDetail job = JobBuilder.newJob(MyJob.class).withIdentity("MyJob", "MyJob_Group")

.usingJobData("author", "认知科技技术团队").build();

//使用jobDateMap

job.getJobDataMap().put("微信公众号", "认知科技技术团队");

//启动

scheduler.start();

//调度假如这个job

scheduler.scheduleJob(job, trigger);

TimeUnit.HOURS.sleep(1);

scheduler.shutdown(true);

}

public static class MyJob implements Job {

@Override

public void execute(JobExecutionContext jobExecutionContext) {

System.out.println("hello begin " + Thread.currentThread().getName());

try {

TimeUnit.SECONDS.sleep(20);

} catch (InterruptedException e) {

throw new RuntimeException(e);

}

System.out.println("hello end " + Thread.currentThread().getName());

}

}

}

1、Java避坑指南:ScheduledThreadPoolExecutor避坑

2、Java避坑指南:ScheduledThreadPoolExecutor避坑之异常信息会丢失,任务不再继续被调度的源码分析