我有一个 Java 程序,它每 20 秒从 Spring Qquartz 执行一次。有时只需几秒钟即可执行,但随着数据变大,我确信它会运行 20 秒或更长时间。
如何防止 Quartz 在一个实例仍在执行时触发/触发作业?解雇 2 个在数据库上执行相同操作的作业不会那么好。有没有办法可以进行某种同步?
我有一个 Java 程序,它每 20 秒从 Spring Qquartz 执行一次。有时只需几秒钟即可执行,但随着数据变大,我确信它会运行 20 秒或更长时间。
如何防止 Quartz 在一个实例仍在执行时触发/触发作业?解雇 2 个在数据库上执行相同操作的作业不会那么好。有没有办法可以进行某种同步?
如果你改变你的类来实现 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*/}
}
在 Quartz 2.0 版中,StatefulJob
已弃用。现在建议改用注解,例如
@DisallowConcurrentExecution
public class YourJob implements org.quartz.Job {
void execute(JobExecutionContext context) {/*implementation omitted*/}
}
以防万一有人引用这个问题,StatefulJob 已被弃用。他们现在建议您改用注释...
@PersistJobDataAfterExecution
@DisallowConcurrentExecution
public class TestJob implements Job {
这将解释这些注释的含义......
注释引起的行为正如它们的名称所描述的那样 - 不允许作业的多个实例同时运行(考虑这样一种情况,即作业在其 execute() 方法中有代码需要 34 秒才能运行,但它被调度为每 30 秒重复一次的触发器),并且在每次执行后将其 JobDataMap 内容重新保存在调度程序的 JobStore 中。就本示例而言,只有 @PersistJobDataAfterExecution 注释是真正相关的,但最好将 @DisallowConcurrentExecution 注释与它一起使用,以防止保存的数据出现竞争条件。
如果您使用弹簧石英,我认为您必须像这样配置
<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>
我不确定你想要同步,因为第二个任务会阻塞直到第一个任务完成,你最终会积压。您可以将作业放入队列中,但根据您的描述,队列可能会无限增长。
我会调查ReadWriteLock,并让您的任务在运行时设置一个锁。未来的任务可以检查此锁,如果旧任务仍在运行,则立即退出。我从经验中发现这是解决这个问题的最可靠方法。
也许还会产生警告,以便您知道遇到问题并相应地增加时间间隔?
把它们排成一个队列
即使时间超过 20 秒,当前作业也应该完成,然后应该从队列中获取下一个作业。
或者您也可以将时间增加到某个合理的数量。
您可以使用信号量。当信号量被取走时,放弃第二个工作,等到下一个触发时间。