2

I have a method that is scheduled to run each X ms.

This method is launching a new method within a new thread.

Nevertheless, I want to delay this method before counting again.

Here is my code:

@Scheduled(fixedRate = RATE_IN_MS)
public void myMethod(){
    new Thread(() -> method()).start();
    Thread.sleep(RATE_IN_MS);
}

The problem is that the behavior is not like I want.

Here is the current behavior:

  1. After RATE_IN_MS myMethod is launched.
  2. method() start running in a different thread.
  3. After RATE_IN_MS myMethod is launched.

The problem: Why does my sleep method didn't delay the next launch of myMethod? RATE_IN_MS (by fixedDelay) + RATE_IN_MS (because of Thread.sleep(RATE_IN_MS) need to be the real delay between them.

What I'm missing here?

Thanks!

Roni Koren Kurtberg
  • 495
  • 1
  • 8
  • 18
  • @ShanuGupta - Why? I am using the same constant RATE_IN_MS. In addition, why they are related each other? even if I would like to sleep for RATE_IN_MS / 2 it needs to be ok. – Roni Koren Kurtberg May 06 '18 at 07:14
  • 1
    https://stackoverflow.com/questions/38842507/what-different-between-fixed-rate-and-fixed-delay-in-schedule-spring – Oleksandr Loushkin May 06 '18 at 07:18
  • because, you are running at fixedRate, no matter what happened with your execution, the thread will call your myMethod(). Use fixedDelay instead. – Naveen May 06 '18 at 07:19
  • I understand that, but if sleep time will be `>` than the fixed rate, how it will affect this scenario? – Roni Koren Kurtberg May 06 '18 at 07:20

3 Answers3

2

I have created this running example for your reference.Execution delay is configured in spring configuration file which can be changed as you wish.

package com.myprgm;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.stereotype.Component;

@Component
@EnableScheduling
public class JobSchdulingServc {
    @Value("${com.executionDelay}")
    private long executionDelay; // in milliseconds,mention in sping property file
    @Autowired
    TaskScheduler taskScheduler;

    @Bean
    public TaskScheduler poolScheduler() {
        return new ThreadPoolTaskScheduler();
    }

    private void stopSceduling(boolean terminateJob) {
        ((ThreadPoolTaskScheduler) taskScheduler).shutdown();
        if (terminateJob) {
            System.exit(1);
        }

    }
    public void scheduleMyJob() {
        taskScheduler.scheduleWithFixedDelay(new Runnable() {
            @Override
            public void run() {
                try {
                    someServiceimpl.generateMyDataAndSendInEveryMilliSeconds(); // service you want to execute after
                    // specified executionDelay
                } catch (Exception e) {
                    stopSceduling(true);
                }
            }

        }, executionDelay);
    }

}
mindSet
  • 231
  • 2
  • 10
1

With fixedRate, the scheduler does not care the time spent in myMethod.

You can use @Scheduled(fixedDelay = RATE_IN_MS). The scheduler will calculate next execution time after finishing myMethod.

xingbin
  • 27,410
  • 9
  • 53
  • 103
0

When using fixedrate scheduling, there are two possible situations as to when the next invocation of myMethod occurs:

  1. if after RATE_IN_MS milliseconds from the last myMethod invocation, myMethod is no longer running, then that's when myMethod will be invoked again.
  2. if after RATE_IN_MS milliseconds from the last myMethod invocation that invocation is still running and it hasn't returned, then this will cause the next scheduled call to be blocked until the current invocation is over.

For example if RATE_IN_MS is 10 ms, let's consider two scenarios:

  1. myMethod takes 5 ms to execute. In this case, a new myMethod invocation will occur every 10 ms because 5 ms is less than 10 ms.
  2. if for some reason the last myMethod invocation took 12 ms to complete, which is longer than 10 ms, then the next one will be queued. So there will be a minimum of 12 ms between invocation which is more than RATE_IN_MS.

Now to answer your question specifically, let's say that RATE_IN_MS is 10 ms, then definitely we have the second case from my above example, however, the wait time will not be multiplied in two as you expect, rather it will be consisted of two time periods:

  1. the time it took myMethod to reach Thread.sleep(RATE_IN_MS) which could be much less than RATE_IN_MS, let's say it's only 3 ms and let's call this time X.
  2. the time the Thread sleeps which is RATE_IN_MS which we are saying it's 10 ms for example.

Then the total time between invocations of myMethod() will be: X+RATE_IN_MS which according to my example is 13 ms and not RATE_IN_MS * 2.

admdev
  • 448
  • 2
  • 9