Java 确保 Spring Quartz 作业执行不重叠

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1636556/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 18:03:31  来源:igfitidea点击:

Ensure that Spring Quartz job execution doesn't overlap

javaspringsynchronizationquartz-scheduler

提问by ant

I have a Java program that executes from Spring Qquartz every 20 seconds. Sometimes it takes just few seconds to execute, but as data gets bigger I'm sure it run for 20 seconds or more.

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

How can I prevent Quartz from firing/triggering the job while one instance is still being executed? Firing 2 jobs performing same operations on a database would not be so good. Is there a way I can do some kind of synchronization?

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

采纳答案by skaffman

If all you need to do is fire every 20 seconds, Quartz is serious overkill. The java.util.concurrent.ScheduledExecutorServiceshould be perfectly sufficient for that job.

如果你需要做的就是每 20 秒触发一次,Quartz 是严重的矫枉过正。本java.util.concurrent.ScheduledExecutorService应是完成此项工作完全足够。

The ScheduledExecutorServicealso provides two semantics for scheduling. "fixed rate"will attempt to run your job every 20 seconds regardless of overlap, whereas "fixed delay"will attempt to leave 20 seconds between the end of the first job and the start of the next. If you want to avoid overlap, then fixed-delay is safest.

ScheduledExecutorService还提供了两个语义用于调度。“固定速率”将尝试每 20 秒运行一次您的作业,而不考虑重叠,而“固定延迟”将尝试在第一个作业结束和下一个作业开始之间留出 20 秒。如果你想避免重叠,那么固定延迟是最安全的。

回答by Asad Khan

put them in a queue

把它们排在队列中

Even if the time exceeds 20 second current job should be finished & then the next should be fetched from the queue.

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

Or you can also increase time to some reasonable amount.

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

回答by Brian Agnew

I'm not sure you want synchronisation, since the second task will block until the first finishes, and you'll end up with a backlog. You could put the jobs in a queue, but from your description it sounds like the queue may grow indefinitely.

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

I would investigate ReadWriteLocks, and let your task set a lock whilst it is running. Future tasks can inspect this lock, and exit immediately if an old task is still running. I've found from experience that that's the most reliable way to approach this.

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

Perhaps generate a warning as well so you know you're encountering problems and increase the time interval accordingly ?

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

回答by Salandur

You can use a semaphore. When the semaphore is taken, abandon the 2nd job and wait until the next fire time.

您可以使用信号量。当信号量被取走时,放弃第二个工作,等待下一次触发时间。

回答by Dónal

Quartz 1

石英 1

If you change your class to implement StatefulJob instead of Job, Quartz will take care of this for you. From the StatefulJob javadoc:

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

stateful jobs are not allowed to execute concurrently, which means new triggers that occur before the completion of the execute(xx) method will be delayed.

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

StatefulJob extends Job and does not add any new methods, so all you need to do to get the behaviour you want is change this:

StatefulJob 扩展了 Job 并且不添加任何新方法,所以你需要做的就是改变你想要的行为:

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

To this:

对此:

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

Quartz 2

石英 2

In version 2.0 of Quartz, StatefulJobis deprecated. It is now recommended to use annotations instead, e.g.

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

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

回答by gshauger

Just in case anyone references this question, StatefulJob has been deprecated. They now suggest you use annotations instead...

以防万一有人提到这个问题,StatefulJob 已被弃用。他们现在建议您改用注释...

@PersistJobDataAfterExecution
@DisallowConcurrentExecution
public class TestJob implements Job {

This will explain what those annotations mean...

这将解释这些注释的含义......

The annotations cause behavior just as their names describe - multiple instances of the job will not be allowed to run concurrently (consider a case where a job has code in its execute() method that takes 34 seconds to run, but it is scheduled with a trigger that repeats every 30 seconds), and will have its JobDataMap contents re-persisted in the scheduler's JobStore after each execution. For the purposes of this example, only @PersistJobDataAfterExecution annotation is truly relevant, but it's always wise to use the @DisallowConcurrentExecution annotation with it, to prevent race-conditions on saved data.

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

回答by Paul

if you use spring quartz, i think you have to configure like this

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

    <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>