what different between fixed rate and fixed delay

2019-03-10 20:47发布

问题:

I am implementing scheduled tasks using spring and i see have 2 type config time that scheduled works again from latest. What different between 2 type this config.

 @Scheduled(fixedDelay = 5000)
    public void doJobDelay() {
        // do anything
    }
  @Scheduled(fixedRate = 5000)
    public void doJobRate() {
        // do anything
    }

回答1:

  • fixedRate : makes Spring run the task on periodic intervals even if the last invocation may still be running.
  • fixedDelay : specifically controls the next execution time when the last execution finishes.

In code:

@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
     */
}


回答2:

"fixedRate" : waits for X millis from the start of previous execution before starting next execution. If current execution exceeds 'fixedRate' interval, the next execution is queued, but only next one. It will not create series of queued executions

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);
}

Output:

Started : 1
Finished : 1 // after 4 seconds
Started : 2 // immediately w/o waiting for 1 sec as specified in fixed rate
Finished : 2 // after 4 seconds
and so on

"fixedDelay" : waits for X millis from the end of previous execution before starting next execution. Doesn't matter how much time current execution is taking, the next execution is started after adding 'fixedDelay' interval to end time of current execution. It will not queue next execution.

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);
}

Output:

Started : 1
Finished : 1 // after 4 seconds Started : 2 // waits for 1 second as specified in fixedDelay Finished : 2 // after 4 seconds Started : 3 // after 1 second
and so on



回答3:

fixedRate: It is used to run the job method in every n milliseconds. It is not important whether the job has already finished its previous task.

fixedDelay: It is used to run the job method sequentially with the given n milliseconds waiting time between tasks.

When to use "fixedRate": fixedRate is appropriate if it is not expected to exceed the size of the memory and the thread pool. If the incoming tasks do not finish quick, it may end up with "Out of Memory exception"

When to use "fixedDelay": If every running task is relevant to each other and they need to wait before the previous one finishes, fixedDelay is suitable. If fixedDelay time is set carefully, it will also let the running threads enough time to finish their jobs before the new task starts



回答4:

Fixed Delay : specifically controls the next execution time when the last execution finishes.

Fixed Rate : makes Spring run the task on periodic intervals even if the last invocation may be still running.



回答5:

One thing which should be clarified is that fixedRate does not mean executions will start with a certain time interval.

If one execution cost too much time (more than the fixed rate), the next execution will only start AFTER the previous one finishes, unless @Async and @EnableAsync are provided. The following source codes which are part of Spring's ThreadPoolTaskScheduler implementation explain why:

@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();
        }
    }
}

You can see that only after the previous task is finished (super.run()), the next task is scheduled (schedule()). With @Async and @EnableAsync, super.run() is an async function which will return immediately, thus the next task does not have to wait for the previous one to actually finish.