Reputation: 515
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:
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!
Upvotes: 2
Views: 5536
Reputation: 468
When using fixedrate
scheduling, there are two possible situations as to when the next invocation of myMethod
occurs:
RATE_IN_MS
milliseconds from the last myMethod
invocation, myMethod
is no longer running, then that's when myMethod
will be invoked again.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:
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.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:
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.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.
Upvotes: 0
Reputation: 241
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);
}
}
Upvotes: 2
Reputation: 28279
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
.
Upvotes: 1