进度弹簧的固定速率和固定延迟有什么不同?

时间:2016-08-09 05:09:55

标签: java spring scheduled-tasks

我正在使用spring实现计划任务,我看到有2个类型的配置时间,计划再次从最新工作。 2配置此配置有什么不同。

blocks

8 个答案:

答案 0 :(得分:28)

  • fixedRate:让Spring定期运行任务,即使是 最后一次调用可能仍在运行。
  • fixedDelay:具体控制下次执行时的时间 最后一次执行结束。

在代码中:

@Scheduled(fixedDelay=5000)
public void updateEmployeeInventory(){
    System.out.println("employee inventory will be updated once only the last updated finished ");
    /**
     * add your scheduled job logic here
     */
}


@Scheduled(fixedRate=5000)
public void updateEmployeeInventory(){
    System.out.println("employee inventory will be updated every 5 seconds from prior updated has stared, regardless it is finished or not");
    /**
     * add your scheduled job logic here
     */
}

答案 1 :(得分:15)

“fixedRate”:在开始下一次执行之前等待上一次执行开始时的X millis。如果当前执行超过'fixedRate'间隔,则下一次执行将排队,但只有下一次执行。它不会创建一系列排队执行

private static int i = 0;

@Scheduled(initialDelay=1000, fixedRate=1000)
public void testScheduling() throws InterruptedException {
    System.out.println("Started : "+ ++i);
    Thread.sleep(4000);
    System.out.println("Finished : "+ i);
}

输出:

  

开始:1
  完成:1 // 4秒后   开始:2 //立即按固定费率指定等待1秒   完成:2 // 4秒后   等等

“fixedDelay”:在开始下一次执行之前等待上一次执行结束时的X millis。无论当前执行花费多少时间,在将“fixedDelay”间隔添加到当前执行结束时间之后开始下一次执行。它不会排队下次执行。

private static int i = 0;

@Scheduled(initialDelay=1000, fixedDelay=1000)
public void testScheduling() throws InterruptedException {
    System.out.println("Started : "+ ++i);
    Thread.sleep(4000);
    System.out.println("Finished : "+ i);
}

输出:

  

开始:1
  完成:1 // 4秒后开始:   2 //在fixedDelay中指定等待1秒   完成:2 // 4秒后   开始:3 // 1秒后   等等

答案 2 :(得分:7)

fixedRate:它用于每n毫秒运行一次作业方法。这项工作是否已完成上一项任务并不重要。

fixedDelay:它用于按顺序运行作业方法,任务之间给定的n毫秒等待时间。

何时使用 " fixedRate" : 如果不期望超过内存和线程池的大小,则fixedRate是合适的。如果传入的任务没有快速完成,最终可能会出现" Out of Memory exception"

何时使用 " fixedDelay": 如果每个正在运行的任务彼此相关并且需要在前一个任务完成之前等待,则fixedDelay是合适的。如果小心设置fixedDelay时间,它还会让正在运行的线程有足够的时间在新任务开始之前完成其工作

答案 3 :(得分:1)

有一点需要澄清的是,fixedRate并不意味着执行会以一定的时间间隔开始。

如果一次执行花费的时间太长(超过固定费率),则下一次执行只会在上一次执行完成后开始 AFTER ,除非@Async@EnableAsync是提供。以下源代码是Spring ThreadPoolTaskScheduler实现的一部分,解释了原因:

@Override
public void run() {
    Date actualExecutionTime = new Date();
    super.run();
    Date completionTime = new Date();
    synchronized (this.triggerContextMonitor) {
        this.triggerContext.update(this.scheduledExecutionTime, actualExecutionTime, completionTime);
        if (!this.currentFuture.isCancelled()) {
            schedule();
        }
    }
}

您可以看到,只有在完成上一个任务(super.run())之后,才会安排下一个任务(schedule())。对于@Async@EnableAsyncsuper.run()是一个异步函数,它将立即返回,因此下一个任务不必等待前一个任务实际完成。

答案 4 :(得分:1)

我们可以使用Spring的@Scheduled批注来运行计划任务,但是基于属性fixedDelayfixedRate,执行的性质会发生变化。

  

fixedDelay属性可确保延迟n   在执行任务的millisecond和   下一次执行任务的finish time

当我们需要确保始终只有一个实例运行时,此属性特别有用。对于依赖的工作,这很有帮助。

  

start time属性在每个fixedRate运行计划的任务   n。它不会检查以前是否执行过   任务。

当任务的所有执行独立时,这很有用。如果我们不希望超出内存和线程池的大小,millisecond应该非常方便。

但是,如果传入的任务没有快速完成,则可能会以“内存不足异常”结束。

答案 5 :(得分:1)

fixedDelay属性可确保在任务执行的完成时间与任务下一次执行的开始时间之间存在n毫秒的延迟。

当我们需要确保始终只运行一个任务实例时,此属性特别有用。对于依赖的工作,这很有帮助。

fixedRate属性每n毫秒运行一次计划任务。它不会检查任务的任何先前执行。

当任务的所有执行独立时,这很有用。如果我们不希望超出内存和线程池的大小,则fixedRate应该非常方便。

但是,如果传入的任务没有快速完成,则可能会以“内存不足异常”结束。

有关更多详细信息,请访问: https://www.baeldung.com/spring-scheduled-tasks

答案 6 :(得分:0)

固定延迟:专门控制上次执行完成时的下一个执行时间。

固定费率:即使最后一次调用仍在运行,Spring也会定期运行任务。

答案 7 :(得分:0)

关于这些方法的作用似乎有冲突的建议。行为可能会改变,具体取决于在Spring上下文中注册的taskSchedulerExecutor bean。我发现@Ammar Akouri的答案是最接近的。

这是我在使用ScheduledThreadPoolExecutor时发现的内容(下面提供了完整的测试源)

  • fixedDelayfixedRate均不允许同时执行任务
  • fixedDelay将等待上一次调用的 end ,然后在将来的固定时间安排新的创新。因此,它一次不会排队多个任务。
  • fixedRate将在每个期间计划一个新的调用。它将一次同时排队多个任务(可能是无限制的),但永远不会同时执行任务。

样本测试(Kotlin / JUnit):

class LearningSchedulerTest {

    private lateinit var pool: ScheduledExecutorService

    @Before
    fun before() {
      pool = Executors.newScheduledThreadPool(2)
    }

    @After
    fun after() {
      pool.shutdown()
    }

    /**
     * See: https://stackoverflow.com/questions/24033208/how-to-prevent-overlapping-schedules-in-spring
     *
     * The documentation claims: If any execution of this task takes longer than its period, then subsequent executions may start late, but will not concurrently execute.
     * https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ScheduledThreadPoolExecutor.html#scheduleAtFixedRate-java.lang.Runnable-long-long-java.util.concurrent.TimeUnit-
     */

    @Test
    fun `scheduleAtFixedRate schedules at fixed rate`() {
      val task = TaskFixture( initialSleep = 0)

      pool.scheduleAtFixedRate({task.run()}, 0, 10, TimeUnit.MILLISECONDS )

      Thread.sleep(15)
      Assert.assertEquals(2, task.invocations.get())

      Thread.sleep(10)
      Assert.assertEquals(3, task.invocations.get())

      Thread.sleep(10)
      // 1 initial and 3 periodic invocations
      Assert.assertEquals(4, task.invocations.get())
    }

    @Test
    fun `scheduleAtFixedRate catches up on late invocations`() {
      val task = TaskFixture(initialSleep = 30)

      pool.scheduleAtFixedRate({task.run()}, 0, 10, TimeUnit.MILLISECONDS )

      Thread.sleep(15) // we see no concurrent invocations
      Assert.assertEquals(1, task.invocations.get())

      Thread.sleep(10) // still no concurrent invocations
      Assert.assertEquals(1, task.invocations.get())

      Thread.sleep(10)

      // 1 initial and 3 periodic invocations
      Assert.assertEquals(4, task.invocations.get())
    }

    @Test
    fun `scheduleWithFixedDelay schedules periodically`() {
      val task = TaskFixture( initialSleep = 0)

      pool.scheduleWithFixedDelay({task.run()}, 0, 10, TimeUnit.MILLISECONDS )

      Thread.sleep(35)

      // 1 initial and 3 periodic invocations
      Assert.assertEquals(4, task.invocations.get())
    }

    @Test
    fun `scheduleWithFixedDelay does not catch up on late invocations`() {
      val task = TaskFixture( initialSleep = 30)

      pool.scheduleWithFixedDelay({task.run()}, 0, 10, TimeUnit.MILLISECONDS )

      Thread.sleep(35)

      // 1 initial invocation, no time to wait the specified 10ms for a second invocation
      Assert.assertEquals(1, task.invocations.get())
    }

    class TaskFixture(val initialSleep: Long) {
      var invocations = AtomicInteger()

      fun run() {
        invocations.incrementAndGet()
        if (invocations.get() == 1){
          Thread.sleep(initialSleep)
        }
      }
    }
}