quartz:阻止jobs.xml中作业的并发实例

Jas*_*n S 42 java concurrency quartz-scheduler

这应该很容易.我正在使用在Apache Tomcat 6.0.18下运行的Quartz,我有一个jobs.xml文件,它设置我每分钟运行的预定作业.

我想做的是,如果在下一个触发时间到来时作业仍然在运行,我不想开始新的工作,所以我可以让旧实例完成.

有没有办法在jobs.xml中指定它(防止并发实例)?

如果没有,有没有办法可以在我的应用程序的Job实现中共享对内存中单例的访问权限(这是通过JobExecutionContext吗?)所以我可以自己处理并发?(并检测先前的实例是否正在运行)


更新:在文档中徘徊之后,这是我正在考虑的几种方法,但要么不知道如何让它们工作,要么存在问题.

  1. 使用StatefulJob.这可以防止并发访问...但我不确定如果我使用它会发生什么其他副作用,我也想避免以下情况:

    假设触发时间是每分钟,即触发器#0 =在时间0,触发器#1 = 60000毫秒,#2 = 120000,#3 = 180000等,并且在时间0的触发器#0触发我的工作需要130000毫秒.使用普通Job,这将执行触发器#1和#2,而作业触发器#0仍在运行.使用StatefulJob,这将按顺序执行触发器#1和#2,紧接在#0结束于130000之后.我不希望这样,我希望#1和#2不运行,并且下一个运行作业的触发器应该发生在#3(180000毫秒).所以我仍然需要使用StatefulJob做其他事情才能让它以我想要的方式工作,所以我认为使用它并没有多大优势.

  2. 使用TriggerListener从vetoJobExecution()返回true.

    虽然实现接口似乎很简单,但我必须弄清楚如何以声明方式设置TriggerListener的一个实例.找不到xml文件的文档.

  3. 使用static我的类所拥有的共享线程安全对象(例如信号量或其他)来实现Job.

    我不喜欢通过staticTomcat/Quartz下的关键字使用单例的想法,不确定是否有副作用.另外,我真的不希望它们成为真正的单身,只是与特定工作定义相关的东西.

  4. 实现我自己的Trigger,它扩展了SimpleTrigger并包含可以运行自己的TriggerListener的共享状态.

    同样,我不知道如何设置XML文件以使用此触发器而不是标准<trigger><simple>...</simple></trigger>.

Ari*_*tis 61

还有一个更简单的解决方案.可以为作业提供DisallowConcurrentExecution注释,以防止多个并发实例在运行.请参阅此处的文档.

链接不断破坏所以这里是相关的样本.

@DisallowConcurrentExecution
public class ColorJob implements Job {
Run Code Online (Sandbox Code Playgroud)

  • 使用DisallowConcurrentExecution批注将当前实例排队等待执行,直到上一个实例完成.如果Job实例已在运行,是否有办法从执行中删除当前实例? (7认同)
  • 请注意,该限制仅适用于具有相同JobKey的作业(通常是这种情况).具有不同JobKeys的作业仍然可以并发执行,即使它们是使用相同的类实现的. (2认同)

Sez*_*rli 23

dimitrisli的答案并不完整,所以这是我的.

当Quartz Job唤醒时,它会将JobExecutionContext返回给您.我假设您想跳过具有相同触发器的作业.

  List<JobExecutionContext> jobs = jobExecutionContext.getScheduler().getCurrentlyExecutingJobs();
            for (JobExecutionContext job : jobs) {
                if (job.getTrigger().equals(jobExecutionContext.getTrigger()) && !job.getJobInstance().equals(this)) {
                    logger.info("There's another instance running, so leaving" + this);
                    return;
                }

            }
Run Code Online (Sandbox Code Playgroud)

我们获取当前的作业上下文并检查是否存在具有相同触发器的先前作业实例.如果是这种情况,我们只是跳过返回.


dim*_*sli 18

当您的Quartz作业醒来时,您可以:

JobDetail existingJobDetail = sched.getJobDetail(jobName, jobGroup);
    if (existingJobDetail != null) {
        List<JobExecutionContext> currentlyExecutingJobs = (List<JobExecutionContext>) sched.getCurrentlyExecutingJobs();
        for (JobExecutionContext jec : currentlyExecutingJobs) {
            if(existingJobDetail.equals(jec.getJobDetail())) {
                //String message = jobName + " is already running.";
                //log.info(message);
                //throw new JobExecutionException(message,false);
            }
        }
        //sched.deleteJob(jobName, jobGroup); if you want to delete the scheduled but not-currently-running job
    }
Run Code Online (Sandbox Code Playgroud)


Ram*_*ses 5

我完成了类似的工作,使我的作业类实现了StatefulJob,确保在当前正在运行的作业完成之前没有其他作业启动.

希望有所帮助;)

PD:我使用JBoss实现它......但我认为这没有任何区别.