Java Quartz定时任务 - 禁止任务并发执行

20

我正在使用Quartz Job来执行特定任务。

我还在我的主应用程序类中安排它的执行,我想要实现的是不允许同时执行此作业的实例。

因此,只有在上一个实例完成后,调度程序才应该执行该作业。

这是我的Job类:

public class MainJob implements Job {

static Logger log = Logger.getLogger(MainJob.class.getName());

@Override
public void execute(JobExecutionContext arg0) throws JobExecutionException {

    GlobalConfig cfg = new GlobalConfig();

    ProcessDicomFiles processDicomFiles = new ProcessDicomFiles();  
    ProcessPdfReportFiles processPdf = new ProcessPdfReportFiles();

    try {

            log.info("1. ---- SCHEDULED JOB -- setStudiesReadyToProcess");
            processDicomFiles.setStudiesReadyToProcess();

            log.info("2. ---- SCHEDULED JOB --- distributeToStudies");
            processDicomFiles.distributeToStudies(cfg.getAssocDir());                

            ...

            //process any incoming PDF file
            log.info("11. ---- SCHEDULED JOB --- processPdfFolder");
            processPdf.processPdfFolder();

        } catch (Exception ex) {
            Logger.getLogger(FXMLDocumentController.class.getName()).log(Level.ERROR, null, ex);
        }

    log.info(">>>>>>>>>>> Scheduled Job has ended .... <<<<<<<<<<<<<<<<<<<<");

    }
}

所以在我的应用程序主类中,我正在启动调度程序:

...
//start Scheduler
    try {             
        startScheduler();
    } catch (SchedulerException ex) {
        log.log(Level.INFO, null, ex);
    }
...

public void startScheduler () throws SchedulerException {

        //Creating scheduler factory and scheduler
        factory = new StdSchedulerFactory();
        scheduler = factory.getScheduler();

        schedulerTimeWindow = config.getSchedulerTimeWindow();

        JobDetailImpl jobDetail = new JobDetailImpl();
        jobDetail.setName("First Job");
        jobDetail.setJobClass(MainJob.class);

        SimpleTriggerImpl simpleTrigger = new SimpleTriggerImpl();
        simpleTrigger.setStartTime(new Date(System.currentTimeMillis() + 1000));
        simpleTrigger.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY);
        simpleTrigger.setRepeatInterval(schedulerTimeWindow);
        simpleTrigger.setName("FirstTrigger");

        //Start scheduler
        scheduler.start();
        scheduler.scheduleJob(jobDetail,simpleTrigger);

}

如果已经有一个MainJob实例在运行,我希望阻止调度程序启动第二个实例...

4个回答

36

只需在作业类顶部使用@DisallowConcurrentExecution注释。

请参阅此官方example或此tutorial关于并发作业执行的内容。


2
仍在寻找一种不需要将作业排队,而是直接跳过它的方法。 - b15

8

你从哪里得到的?根据链接的评论,他的意思是DisallowConcurrentExecution只有在正确设置了集群后才能正常工作,而不是不能跨节点工作。 - João Portela

5

1
StatefulJob已经被弃用(不确定是否在05.2015)。DisallowConcurrentExecution和/或PersistJobDataAfterExecution是正确的方法。 - aProgger

1

当使用 @DisallowConcurrentExecution 方法和 @Async 时,从作业执行时要小心。

第二个线程 可能会与 第一个线程 冲突。


如果第二个线程可能与第一个线程冲突会发生什么?您的意思是Execute方法是异步的,会有这样的冲突吗? - Saige Zhang
我认为这展示了如何使用async和DisallowConcurrentExecution https://damienbod.com/2021/11/08/asp-net-core-scheduling-with-quartz-net-and-signalr-monitoring/ - andrew pate
@SaigeZhang 如果 @Async 方法中的业务逻辑需要很长时间才能执行,而且 Job 经常被执行(例如 CRON: '0/10 * * ? * *'),这可能会导致两个异步线程更改相同的数据。您需要明确设置哪些任务已经在进行中,以便为 Job 进行处理。 - polyackov_ot

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接