Quartz

1.核心概念

  • Scheduler(任务调度器)
  • Trigger(触发器)
  • JobDetail(任务详情)
  • Job(具体任务)

1.Scheduler
任务调度器, 通过触发器(Trigger)任务详情(JobDetail)来调度、暂停、删除任务, 调度器可以看作一个独立运行的容器, 通过将TriggerJobDetail注册到Scheduler 中, 两者在Scheduler中拥有各自的组和名称

组和名称是Scheduler查询某一对象的依据, Trigger的组和名称必须唯一, JobDetail的组和名称也必须唯一(但可以跟Trigger相同, 因为两者是不同类型)

Scheduler是一个接口

2.Trigger
触发器, 描述Job执行的时间触发规则, 有两个子类: SimpleTriggerCronTrigger,

SimpleTrigger适合仅调度一次、以固定时间间隔周期执行的调度
CronTrigger可以通过Cron表达式定义出各种复杂时间规则的调度方案, 适合更灵活、更复杂的任务调度需求

3.JobDetail
任务详情, 包括了任务的唯一标识以及具体要执行的任务, 可以通过JobDataMap往任务中传递数据

4.Job
具体任务, 是一个接口, 只定义一个方法execute()方法包含了执行任务的具体方法

1.1 核心概念图

  • Job: 要做什么事情
  • JobDetail: 封装这个任务, 设置组和名称
  • Trigger: 什么时候去做
  • Scheduler: 什么时候去做什么事情

请添加图片描述
一个Scheduler可以注册多个JobDetail和Trigger

2 简单实现

  • 任务
public class MyJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println("执行任务");
    }
}
  • 初始化任务详情和触发器, 并装载到调度器中, 让调度器去执行
public static void main(String[] args) {
   // 任务详情
    JobDetail JobDetail = JobBuilder.newJob(MyJob.class)
            .withIdentity("job1", "group1")
            .build();

    // 触发器
    Trigger trigger = TriggerBuilder.newTrigger()
            .withIdentity("trigger1", "group1")
            // 执行计划, 以1秒的间隔执行, 周期性执行
            .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(1).repeatForever())
            .startNow()
            .build();

    try {
        // 调度器
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        scheduler.scheduleJob(JobDetail, trigger);  // 装载任务和触发器
        scheduler.start();  // 开启定时任务
    } catch (SchedulerException e) {
        e.printStackTrace();
    }
}

注意点: Scheduler每次执行, 都会根据jobDetail创建一个新的job对象, 这样可以规避并发访问的问题(job是多例的, jobDetail也是多例的)

Quartz定时任务默认都是并发执行的, 不会等待上一个任务执行完毕, 只要时间间隔到了, 就会执行. 如果定时任务执行时间太久, 会长时间占用资源, 导致其他任务阻塞

2.1 在运行时, 通过JobDataMap向Job传递数据

  • 创建JobDetail(类似于一个Map), 设置需要传递的值, 最后在初始化JobDetail或者Trigger时作为参数传入
JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put("name", "zhangsan");
jobDataMap.put("age", 15);
jobDataMap.put("money", 128.2);

// 任务详情
JobDetail JobDetail = JobBuilder.newJob(MyJob.class)
        .withIdentity("job1", "group1")
        .usingJobData(jobDataMap)
        .build();
  • 在Job中获取JobDataMap并访问数据
    可以使用getMergedJobDataMap将jobData和triggerData合并在一起, 但会出现相同key被覆盖的情况
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
    JobDataMap jobData = jobExecutionContext.getJobDetail().getJobDataMap();
    String name = jobData.getString("name");
    int age = jobData.getInt("age");
    double money = jobData.getDouble("money");
    System.out.println(name + age + money);

    // 从trigger中获取传递的参数
    // JobDataMap triggerData = jobExecutionContext.getTrigger().getJobDataMap();

    // 将JobDetail和Trigger
    // JobDataMap mergedJobDataMap = jobExecutionContext.getMergedJobDataMap();
}

2.2 每次调度任务时, 都会创建新的Job、JobDetail、Trigger

public class MyJob implements Job {
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        System.out.println("job=" + System.identityHashCode(context));
        System.out.println("jobDetail=" + System.identityHashCode(context.getJobDetail()));
        System.out.println("trigger=" + System.identityHashCode(context.getTrigger()));
        System.out.println("scheduler=" + System.identityHashCode(context.getScheduler()));
    }
}

scheduler在每次调度任务时, 都会创建新的Job、JobDetail、Trigger, 每个任务调度使用新的JobDetail 和Trigger 对象可以保证任务之间的独立性和隔离性。这样可以避免任务之间的相互影响,提高系统的稳定性和可靠性。

在这里插入图片描述

2.3 Quartz定时任务默认都是并发执行的,不会等待上一次任务执行完毕

public class MyJob implements Job {
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        System.out.println("execute:" + new Date());
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

设置的时间间隔是1秒, 但是job中需要执行3秒, 但是每次执行定时任务, 并没有等上一次执行结束才开始, 这说明了每次执行定时任务都是并发的, 定时任务之间相互隔离, 也印证了每次调度任务时, 都会创建新的Job、JobDetail、Trigger

在这里插入图片描述

2.4 串行执行定时任务

@DisallowConcurrentExecution禁止并发执行多个相同定义的JobDetail, 这个注解是加在Job类上的, 但意思并不是不能同时执行多个Job, 而是不能并发执行同一个Job Definition(由JobDetail定义), 但是可以同时执行多个不同的JobDetail

@DisallowConcurrentExecution
public class MyJob implements Job {

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        System.out.println("execute:" + new Date());

        System.out.println("job=" + System.identityHashCode(context));
        System.out.println("jobDetail=" + System.identityHashCode(context.getJobDetail()));
        System.out.println("trigger=" + System.identityHashCode(context.getTrigger()));
        System.out.println("scheduler=" + System.identityHashCode(context.getScheduler()));

        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

使用@DisallowConcurrentExecution, 依旧是创建新的Job、JobDetail、Trigger, 但是执行的时间间隔会受到job执行时间的影响

在这里插入图片描述

@DisallowConcurrentExecution的作用: 确保定时任务串行执行, 这意味着如果一个定时任务是间隔执行, 下一个任务的执行会等待上一个任务执行完毕才开始

2.4 持久化JobDetail中的JobDataMap

我们在JobDataMap中设置count为1, 然后在job对这个值进行累加

因为Job、JobDetail都是每次执行定时任务时新建的, 所以JobDataMap也不是同一个对象. 所以我们如果想让JobDataMap在一个定时任务中被共享(job、jobDetail), 需要添加@PersistJobDataAfterExecution注解

@DisallowConcurrentExecution
@PersistJobDataAfterExecution
public class MyJob implements Job {

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
        int count = jobDataMap.getInt("count");
        System.out.println("count:" + count);
        
        jobDataMap.put("count", jobDataMap.getInt("count") + 1);
    }
}

注意: 持久化只针对于JobDetail中的JobDataMap(对于Tigger中的JobDataMap无效)

2.5 有状态的Job和无状态的Job

在Quartz中, 默认的Job是无状态的

  • 无状态的Job

  • 有状态的Job

相关推荐

  1. <span style='color:red;'>Quartz</span>

    Quartz

    2024-03-22 06:16:02      40 阅读
  2. Quartz 介绍

    2024-03-22 06:16:02       26 阅读
  3. SpringBoot整合Quartz

    2024-03-22 06:16:02       51 阅读
  4. Quartz项目实际使用

    2024-03-22 06:16:02       42 阅读
  5. Quartz.Net(1)

    2024-03-22 06:16:02       37 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-22 06:16:02       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-22 06:16:02       101 阅读
  3. 在Django里面运行非项目文件

    2024-03-22 06:16:02       82 阅读
  4. Python语言-面向对象

    2024-03-22 06:16:02       91 阅读

热门阅读

  1. 26. 删除有序数组中的重复项 (Swift版本)

    2024-03-22 06:16:02       35 阅读
  2. Python爬虫实战:爬取太平洋网络相机文章

    2024-03-22 06:16:02       38 阅读
  3. Vue 小知识点

    2024-03-22 06:16:02       45 阅读
  4. 【Unity】FacebookSDK接入

    2024-03-22 06:16:02       41 阅读
  5. BERT 论文阅读笔记

    2024-03-22 06:16:02       65 阅读
  6. 数据仓库数据质量监控

    2024-03-22 06:16:02       44 阅读
  7. 贪心算法问题

    2024-03-22 06:16:02       40 阅读
  8. 谷歌浏览器(Google Chrome) 常用快捷键和扩展程序

    2024-03-22 06:16:02       85 阅读
  9. 数据结构奇妙旅程之贪心算法

    2024-03-22 06:16:02       46 阅读
  10. SQL语句每日一练二

    2024-03-22 06:16:02       43 阅读