public class MultiCronMain {
    public static void main(String[] args) throws SchedulerException {
        // 2. 调度多个 cron 表达式
        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        scheduler.start();

        // 创建 JobDetail(只创建一次)
        JobDetail job = JobBuilder.newJob(MyJob.class)
                .withIdentity("myJob", "group1")
                .build();

        // 多个 cron 表达式
        String[] cronExpressions = {
                // 20秒执行一次
                "0/20 * * * * ?",
                "0/2 55 19 * * ?",
        };

        int i = 1;

        Set<Trigger> triggersForJob = new HashSet<>();
        for (String cron : cronExpressions) {
            Trigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity("trigger-" + i++, "group1")
                    .withSchedule(CronScheduleBuilder.cronSchedule(cron))
                    .build();
            triggersForJob.add(trigger);
        }
        // 注意:job 是同一个!
        scheduler.scheduleJob(job, triggersForJob, true);

    }
} 

你这段代码是使用 Quartz Scheduler 实现 同一个 Job 被多个 Cron 表达式触发 的标准做法。下面逐行解析其含义和关键点:


✅ 整体目标

MyJob 这个任务,按照两个不同的 cron 规则执行:

  1. 每 20 秒执行一次(0/20 * * * * ?
  2. 每天 19:55 开始,每 2 秒执行一次(0/2 55 19 * * ?

🔍 代码逐段解析

1. 创建调度器并启动
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.start();
  • 获取默认的 Quartz 调度器实例;
  • 启动调度器(开始监听触发事件)。

2. 定义 JobDetail(任务模板)
JobDetail job = JobBuilder.newJob(MyJob.class)
        .withIdentity("myJob", "group1")
        .build();
  • MyJob.class:你实现的 Job 接口类;
  • .withIdentity("myJob", "group1"):给这个任务起个唯一标识(名称 + 组名);
  • 注意:这里只创建 一个 JobDetail,代表“任务本身”,不包含调度时间。

📌 JobDetail 是任务的“蓝图”,可以被多个 Trigger 引用。


3. 定义多个 cron 表达式
String[] cronExpressions = {
    "0/20 * * * * ?",   // 每20秒一次(全天)
    "0/2 55 19 * * ?",  // 每天19:55:00、19:55:02...19:55:58
};
  • 两个合法的 Quartz cron 表达式(6位,含秒,结尾用 ?)。

4. 为每个 cron 创建 Trigger 并收集到 Set 中
Set<Trigger> triggersForJob = new HashSet<>();
for (String cron : cronExpressions) {
    Trigger trigger = TriggerBuilder.newTrigger()
            .withIdentity("trigger-" + i++, "group1")
            .withSchedule(CronScheduleBuilder.cronSchedule(cron))
            .build();
    triggersForJob.add(trigger);
}
  • 每个 cron 表达式生成一个独立的 CronTrigger
  • 每个 Trigger 有唯一 ID(如 trigger-1, trigger-2);
  • 所有 Trigger 放入一个 Set 集合。

✅ 这是关键:多个 Trigger → 同一个 Job


5. 一次性将 Job 和多个 Trigger 关联
scheduler.scheduleJob(job, triggersForJob, true);
  • 这是 Quartz 提供的批量调度方法
    void scheduleJob(JobDetail jobDetail, Set<? extends Trigger> triggersForJob, boolean replace)
    
  • job:任务模板;
  • triggersForJob:所有要绑定的触发器;
  • true:如果已存在同名 Job,是否替换(replace = true)。

效果:Quartz 内部会将这个 JobDetail 与多个 Trigger 建立关联。
每当任意一个 Trigger 触发,就会执行 MyJob.execute() 方法。


⚠️ 重要注意事项

1. Job 必须是无状态的(或线程安全)
  • 因为两个 Trigger 可能 同时触发(比如在 19:55:00 时,第一个 cron 也可能刚好到 20 秒整点);
  • 如果 MyJob 有共享变量或非线程安全操作,需加锁或使用 @DisallowConcurrentExecution 注解:
@DisallowConcurrentExecution
public class MyJob implements Job {
    public void execute(JobExecutionContext context) { ... }
}
2. Trigger 的命名必须唯一
  • 你在循环中用 i++ 确保了 trigger-1, trigger-2 不重复,这是正确的。
3. 表达式格式是 Quartz 特有的
  • 0/20 * * * * ?:每 20 秒(秒字段)
  • 0/2 55 19 * * ?:19:55 分,每 2 秒
  • 结尾的 ? 表示“不指定星期几”(Quartz 要求“日”和“周”互斥)

✅ 执行效果示例

假设当前时间是 19:55:00

  • Trigger 1:如果当前秒是 0、20、40,则触发;
  • Trigger 2:在 19:55:00、19:55:02、19:55:04 …… 19:55:58 触发;

所以 19:55:00、19:55:20、19:55:40 这三个时刻,两个 Trigger 会同时触发,导致 MyJob 被并发执行两次(除非你加了 @DisallowConcurrentExecution)。


💡 总结:这段代码的核心思想

“一个任务逻辑(Job),多个调度规则(Trigger)”
通过 Quartz 的 scheduleJob(JobDetail, Set<Trigger>, ...) 方法,
实现 复用同一个 Job 类,按不同时间策略执行,避免代码重复。

这是 Quartz 中 最佳实践,完全符合其设计哲学。

✅ 你的代码写法 正确且高效

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐