确保Spring Quartz作业执行不重叠

问题描述 投票:43回答:7

我有一个Java程序,每20秒从Spring Qquartz执行一次。有时执行只需几秒钟,但随着数据变大,我确信它会运行20秒或更长时间。

当一个实例仍在执行时,如何防止Quartz触发/触发作业?在数据库上执行2个执行相同操作的作业并不是那么好。有没有办法可以做某种同步?

java spring synchronization quartz-scheduler
7个回答
31
投票

如果您需要做的就是每20秒发射一次,那么Quartz就会严重过度杀伤。 java.util.concurrent.ScheduledExecutorService应该完全适合这项工作。

ScheduledExecutorService还为调度提供了两种语义。 "fixed rate"将尝试每20秒运行一次你的工作而不管重叠,而"fixed delay"将尝试在第一份工作结束和下一次工作开始之间离开20秒。如果你想避免重叠,那么固定延迟是最安全的。


132
投票

石英1

如果你改变你的类来实现StatefulJob而不是Job,Quartz会为你处理这个问题。来自StatefulJob javadoc

不允许有状态作业同时执行,这意味着在执行(xx)方法完成之前发生的新触发器将被延迟。

StatefulJob扩展了Job并且没有添加任何新方法,所以你需要做的就是改变这个:

public class YourJob implements org.quartz.Job {
    void execute(JobExecutionContext context) {/*implementation omitted*/}
}

对此:

public class YourJob implements org.quartz.StatefulJob {
    void execute(JobExecutionContext context) {/*implementation omitted*/}
}

石英2

在Quartz 2.0版本中,StatefulJob已被弃用。现在建议使用注释,例如

@DisallowConcurrentExecution
public class YourJob implements org.quartz.Job {
    void execute(JobExecutionContext context) {/*implementation omitted*/}
}

17
投票

如果有人引用此问题,则StatefulJob已被弃用。他们现在建议你使用注释代替......

@PersistJobDataAfterExecution
@DisallowConcurrentExecution
public class TestJob implements Job {

这将解释那些注释意味着什么......

注释会引起行为,就像它们的名称所描述的那样 - 不允许多个作业实例同时运行(考虑一个作业在其execute()方法中有代码运行需要34秒才能运行的情况,但是它被调度为触发器每30秒重复一次),并在每次执行后将JobDataMap内容重新保存在调度程序的JobStore中。出于此示例的目的,只有@PersistJobDataAfterExecution批注才真正相关,但使用@DisallowConcurrentExecution批注始终是明智的,以防止保存数据的竞争条件。


4
投票

如果你使用弹簧石英,我认为你必须这样配置

    <bean id="batchConsumerJob"class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <property name="targetObject" ref="myScheduler" />
        <property name="targetMethod" value="execute" />
        <property name="concurrent" value="false" />
    </bean>

2
投票

我不确定你是否想要同步,因为第二个任务将阻塞直到第一个完成,你最终会得到一个积压。您可以将作业放在队列中,但从您的描述中可以看出队列可能会无限增长。

我会调查ReadWriteLocks,让你的任务在运行时锁定。未来的任务可以检查此锁定,并在旧任务仍在运行时立即退出。我从经验中发现,这是解决这个问题最可靠的方法。

也许还会产生警告,以便您知道自己遇到问题并相应地增加时间间隔?


0
投票

把它们放在队列中

即使时间超过20秒,也应该完成当前作业,然后从队列中取出下一个作业。

或者您也可以将时间增加到合理的数量。


0
投票

您可以使用信号量。当信号量被拿走时,放弃第二个工作并等到下一个火灾时间。

© www.soinside.com 2019 - 2024. All rights reserved.