确保Spring Quartz作业执行不重叠
我有一个Java程序,每20秒执行一次Spring Qquartz。 有时只需要几秒钟的时间来执行,但随着数据变得更大,我相信它会运行20秒或更长时间。
在一个实例仍在执行的情况下,如何防止Quartz触发/触发作业? 在数据库上执行相同操作的2个作业不会那么好。 有什么办法可以做一些同步吗?
如果你所要做的只是每20秒触发一次,Quartz是严重的矫枉过正。 java.util.concurrent.ScheduledExecutorService
对于这个工作应该是完全足够的。
ScheduledExecutorService
还提供了两个调度语义。 “固定费率”将尝试每隔20秒运行一次,而不考虑重叠,而“固定延迟”将尝试在第一份工作结束和下一次工作结束之间离开20秒。 如果你想避免重叠,那么固定延迟是最安全的。
石英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*/} }
为了防止任何人引用这个问题,StatefulJob已经被弃用了。 他们现在build议你使用注释,而不是…
@PersistJobDataAfterExecution @DisallowConcurrentExecution public class TestJob implements Job {
这将解释这些注释是什么意思…
注释导致行为就像他们的名字描述一样 – 作业的多个实例将不被允许同时运行(考虑一个作业的execute()方法中有代码需要运行34秒的情况,但是它的计划是用一个触发器每30秒重复一次),并在每次执行后将其JobDataMap内容重新保留在调度程序的JobStore中。 就本示例而言,只有@PersistJobDataAfterExecution注释是真正相关的,但使用@DisallowConcurrentExecution注释总是明智的,以防止保存数据的竞争条件。
如果你使用弹簧石英,我认为你必须像这样configuration
<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秒,当前的工作应该完成,然后下一个应该从队列中提取。
或者你也可以增加一些合理的时间。
你可以使用信号量。 当信号被占用时,放弃第二个工作,等到下一次着火时间。