Java quartz:在jobs.xml中防止作业的并发实例

Java quartz:在jobs.xml中防止作业的并发实例,java,concurrency,quartz-scheduler,Java,Concurrency,Quartz Scheduler,这应该很容易。我正在使用ApacheTomcat6.0.18下运行的Quartz,我有一个可以设置每分钟运行的计划作业的程序 我想做的是,如果在下一个触发时间到来时作业仍在运行,我不想启动新作业,所以我可以让旧实例完成 有没有办法在jobs.xml(防止并发实例)中指定这一点 如果没有,是否有一种方法可以在我的应用程序实现中共享对内存中单例的访问(是否通过?),以便我自己处理并发?(并检测上一个实例是否正在运行) 更新:在文档中苦苦挣扎之后,我正在考虑几种方法,但要么不知道如何让它们发挥作用,

这应该很容易。我正在使用ApacheTomcat6.0.18下运行的Quartz,我有一个可以设置每分钟运行的计划作业的程序

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

有没有办法在jobs.xml(防止并发实例)中指定这一点

如果没有,是否有一种方法可以在我的应用程序实现中共享对内存中单例的访问(是否通过?),以便我自己处理并发?(并检测上一个实例是否正在运行)


更新:在文档中苦苦挣扎之后,我正在考虑几种方法,但要么不知道如何让它们发挥作用,要么存在问题

  • 使用。这会阻止并发访问。。。但我不确定如果我使用它会产生什么其他副作用,我也希望避免以下情况:

    假设触发时间为每分钟一次,即触发时间为0时,触发时间为1=60000msec,触发时间为2=120000,触发时间为3=180000,等等。触发时间为0时,触发时间为0时,触发时间为130000秒,触发我的作业。对于普通作业,这将在作业触发器0仍在运行时执行触发器1和触发器2。对于StatefulJob,它将在0在130000处结束后立即按顺序执行触发器1和2。我不希望这样,我希望1和2不运行,运行作业的下一个触发器应该在3(180000秒)发生。因此,我仍然需要对StatefulJob做一些其他的事情,才能让它按我想要的方式工作,所以我认为使用它没有什么好处

  • 使用从vetoJobExecution()返回true

    虽然实现接口看起来很简单,但我必须弄清楚如何以声明方式设置TriggerListener的一个实例

  • 使用我实现作业的类所拥有的
    静态
    共享线程安全对象(例如信号量或任何东西)

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

  • 实现my own,它扩展并包含可以运行自己的TriggerListener的共享状态

    同样,我不知道如何设置XML文件以使用此触发器,而不是标准的


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

    希望有帮助;)


    我用JBoss实现了它。。。但我不认为这有什么区别。

    当你的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
    }
    
    JobDetail existingJobDetail=sched.getJobDetail(jobName,jobGroup);
    如果(existingJobDetail!=null){
    List currentlyExecutingJobs=(List)sched.getCurrentlyExecutingJobs();
    for(JobExecutionContext jec:CurrentlyExecutionJobs){
    if(existingJobDetail.equals(jec.getJobDetail())){
    //字符串消息=jobName+“已在运行。”;
    //日志信息(消息);
    //抛出新JobExecutionException(消息,false);
    }
    }
    //sched.deleteJob(jobName,jobGroup);如果要删除计划但当前未运行的作业
    }
    
    能否将作业设置为StatefulJob,并为您创建的每个触发器设置作业的Misfire指令,使其在丢失时不触发?不确定您使用的是哪种类型的作业,但您必须对适用于触发器类型的缺火说明进行一些研究

    谢谢,
    迪米特里斯利的答案不完整,所以这是我的

    当Quartz作业唤醒时,它会将其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;
        }
    }
    
    List jobs=jobExecutionContext.getScheduler().getCurrentlyExecutionJobs();
    for(JobExecutionContext作业:作业){
    if(job.getTrigger().equals(jobExecutionContext.getTrigger())&&!job.getJobInstance().equals(this)){
    info(“有另一个实例正在运行,所以留下“+this”);
    返回;
    }
    }
    

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

    还有另一个更简单的解决方案。可以为作业指定一个DisallowConcurrentExecution注释,该注释可防止多个并发实例运行。见文件

    链接一直断开,因此下面是相关示例

    @DisallowConcurrentExecution
    public class ColorJob implements Job {
    

    scaramouche溶液的轻微变化

    List<JobExecutionContext> jobs = jobExecutionContext.getScheduler().getCurrentlyExecutingJobs();
    for (JobExecutionContext job : jobs) {
        if (job.getTrigger().equals(jobExecutionContext.getTrigger()) && !job.getFireInstanceId().equals(jobExecutionContext.getFireInstanceId()) {
            logger.info("There's another instance running, so leaving" + this);
            return;
        }
    
    }
    
    List jobs=jobExecutionContext.getScheduler().getCurrentlyExecutionJobs();
    for(JobExecutionContext作业:作业){
    if(job.getRigger().equals(jobExecutionContext.getRigger())&&!job.getFireInstanceId().equals(jobExecutionContext.getFireInstanceId()){
    info(“有另一个实例正在运行,所以留下“+this”);
    返回;
    }
    }
    

    如果所有作业执行都使用单个实例(使用自定义JobFactory类返回单例,而不是每次执行调用newInstance()),scaramouche的解决方案就会失败。

    如果您使用的是
    org.springframework.scheduling.quartz.QuartzJobBean

    受保护的void executeInternal(JobExecutionContext上下文)引发JobExecutionException{
    试一试{
    调度器调度器=context.getScheduler();
    List jobs=scheduler.getCurrentlyExecutingJobs();
    for(JobExecutionContext作业:作业){
    if(job.getTrigger().equals(context.getTrigger())&&job.getJobDetail()!=context.getJobDetail()){
    LOG.warn(“忽略!”);
    返回;
    }
    }
    ...
    }捕获(调度){
    LOG.error(“真幸运!:”(,e);
    }