确保Spring Quartz作业执行不重叠

时间:2009-10-28 11:00:38

标签: java spring synchronization quartz-scheduler

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

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

7 个答案:

答案 0 :(得分:133)

石英1

如果您更改类以实现StatefulJob而不是Job,Quartz将为您处理此问题。来自StatefulJob javadoc

  

不允许有状态的工作   并发执行,这意味着新的   在之前发生的触发器   完成execute(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*/}
}

答案 1 :(得分:31)

如果你需要做的就是每20秒开火一次,石英就会严重过度杀伤。 java.util.concurrent.ScheduledExecutorService应该足以完成这项工作。

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

答案 2 :(得分:18)

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

@PersistJobDataAfterExecution
@DisallowConcurrentExecution
public class TestJob implements Job {

这将解释这些注释的意思......

  

注释会导致行为   他们的名字描述 - 多个   工作的实例不会   允许同时运行(考虑   作业中包含代码的情况   execute()方法需要34秒   运行,但它安排了一个   触发器每30次重复一次   秒),并将拥有其JobDataMap   内容重新保留在   调度程序的JobStore在每个之后   执行。出于此目的   仅举例说明   @PersistJobDataAfterExecution   注释是真正相关的,但它是   总是明智地使用   @DisallowConcurrentExecution   用它来注释,以防止   保存数据的竞争条件。

答案 3 :(得分: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>

答案 4 :(得分:2)

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

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

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

答案 5 :(得分:0)

将它们放入队列

即使时间超过20秒,也应该完成当前的工作。那么下一个应该从队列中获取。

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

答案 6 :(得分:0)

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