scheduleAtFixedRate vs scheduleWithFixedDelay - java

What's the main difference between scheduleAtFixedRate and scheduleWithFixedDelay methods of ScheduledExecutorService?
scheduler.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
System.out.println("scheduleAtFixedRate: " + new Date());
}
}, 1, 3L , SECONDS);
scheduler.scheduleWithFixedDelay(new Runnable() {
#Override
public void run() {
System.out.println("scheduleWithFixedDelay: " + new Date());
}
}, 1, 3L , SECONDS);
they print exact the same time, seems they are executed at exact the same interval.

Try adding a Thread.sleep(1000); call within your run() method... Basically it's the difference between scheduling something based on when the previous execution ends and when it (logically) starts.
For example, suppose I schedule an alarm to go off with a fixed rate of once an hour, and every time it goes off, I have a cup of coffee, which takes 10 minutes. Suppose that starts at midnight, I'd have:
00:00: Start making coffee
00:10: Finish making coffee
01:00: Start making coffee
01:10: Finish making coffee
02:00: Start making coffee
02:10: Finish making coffee
If I schedule with a fixed delay of one hour, I'd have:
00:00: Start making coffee
00:10: Finish making coffee
01:10: Start making coffee
01:20: Finish making coffee
02:20: Start making coffee
02:30: Finish making coffee
Which one you want depends on your task.

Visualize time series of invocation scheduleAtFixedRate method. Next executions will start immediately if the last one takes longer than period. Otherwise, it will start after period time.
Time series of invocation scheduleWithFixedDelay method. Next execution will start after delay time between termination of one execution and the commencement of the next, regardless of its execution time
Hope can help you

The scheduleAtFixedRate() method creates a new task and submits it to the executor every period, regardless of whether or not the previous task finished.
On the other hand, the scheduleWithFixedDelay() method creates a new task after the previous task has finished.

If you read the Java Doc it will be clearer
ScheduledFuture scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)
Creates and executes a periodic action that becomes enabled first after the given initial delay, and subsequently with the given period; that is executions will commence after initialDelay then initialDelay+period, then initialDelay + 2 * period, and so on.
ScheduledFuture scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)
Creates and executes a periodic action that becomes enabled first after the given initial delay, and subsequently with the given delay between the termination of one execution and the commencement of the next.

There is one catch in scheduleAtFixedRate if first thread is taking too long and not ended in given duration then second conscutive thread will not start once the first task will get finsished and will not imediately get started while the first thread has comepleted their task and gievn duration has been elapsed. JVM Will decide when the next task will get executed .
I think that will help you to choose method Becuase due to this i got big problem

I can see your premiss but your conclusion is not quite right.
Here is a good and quite complete explanation according to this Tutorial for understanding the diferences bitween these two.
scheduleAtFixedRate (Runnable, long initialDelay, long period, TimeUnit timeunit)
This method schedules a task to be executed periodically. The task is executed the first time after the initialDelay, and then recurringly every time the period expires.
If any execution of the given task throws an exception, the task is no longer executed. If no exceptions are thrown, the task will continue to be executed until the ScheduledExecutorService is shut down.
If a task takes longer to execute than the period between its scheduled executions, the next execution will start after the current execution finishes. The scheduled task will not be executed by more than one thread at a time.
scheduleWithFixedDelay (Runnable, long initialDelay, long period, TimeUnit timeunit)
This method works very much like scheduleAtFixedRate() except that the period is interpreted differently.
In the scheduleAtFixedRate() method the period is interpreted as a delay between the start of the previous execution, until the start of the next execution.
In this method, however, the period is interpreted as the delay between the end of the previous execution, until the start of the next. The delay is thus between finished executions, not between the beginning of executions.

Let's write a simple program:
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
var time = 0L
var start = System.currentTimeMillis()
val executor = Executors.newScheduledThreadPool(1)
executor.scheduleWithFixedDelay({
if (time >= 12_000L) {
executor.shutdown()
} else {
Thread.sleep(2000L)
val now = System.currentTimeMillis()
time += now - start
System.out.println("Total $time delay ${now - start}\n")
start = now
}
}, 0L, 1000L, TimeUnit.MILLISECONDS)
And see the results:
| scheduleWithFixedDelay | scheduleAtFixedRate |
|:----------------------:|:----------------------:|
| Total 2001 delay 2001 | Total 2003 delay 2003 |
| Total 5002 delay 3001 | Total 4004 delay 2001 |
| Total 8003 delay 3001 | Total 6004 delay 2000 |
| Total 11003 delay 3000 | Total 8004 delay 2000 |
| Total 14003 delay 3000 | Total 10005 delay 2001 |
| --- | Total 12005 delay 2000 |
NOTICE the execution time is bigger than waiting
scheduleWithFixedDelay keeps delay
scheduleAtFixedRate removes delay

scheduledExecutorService.scheduleAtFixedRate(() -> {
System.out.println("runnable start"); try { Thread.sleep(5000); System.out.println("runnable end");} catch
(InterruptedException e) { // TODO Auto-generated catch block
e.printStackTrace(); }}, 2, 7, TimeUnit.SECONDS);
scheduledExecutorService.scheduleWithFixedDelay(() -> {
System.out.println("runnable start"); try { Thread.sleep(5000); System.out.println("runnable end");} catch
(InterruptedException e) { // TODO Auto-generated catch block
e.printStackTrace(); } }, 2, 7, TimeUnit.SECONDS);
Just execute it, and you will know the difference. Thank you

Related

Spring Java #Scheduling configuration

Using #Scheduling to run method at #Scheduled(fixedRate = 10000) and set up #Scheduling threading by implementing SchedulingConfigurer
#Bean(destroyMethod="shutdown")
public Executor taskExecutor() {
return Executors.newScheduledThreadPool(10);
}
if I used Thread.sleep or Lock , no other thread is created by Executor unless Thread.sleep wake up or lock is cleared.
Can someone explain internal working if i have 10 pool size they 10 threads should be created at rate of 10000 millisec.
Basically such behavior comes from ScheduledExecutorService implementation which is used internally by spring. If you will run this code you will notice the same behavior:
public static void main(String[] args) throws Exception {
ScheduledExecutorService executor = Executors.newScheduledThreadPool(10);
executor.schedule(() -> {
System.out.println("Running task in thread " + Thread.currentThread().getId());
try {
Thread.sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {
System.out.println("interrupted while sleeping");
}
}, 1000, TimeUnit.MILLISECONDS);
Thread.sleep(10000);
executor.shutdownNow();
}
When you submit task to scheduled thread pool it is wrapped with RunnableScheduledFuture which is passed to delayedExecute method. This method adds the task to the tasks queue and starts new worker if current number of workers is less than corePoolSize. Worker tries to get a task from the queue and process it invoking run method. There is a dedicated DelayedWorkQueue implementation which returns tasks only if they are ready for execution. Here is how run method of RunnableScheduledFuture looks like:
/**
* Overrides FutureTask version so as to reset/requeue if periodic.
*/
public void run() {
boolean periodic = isPeriodic();
if (!canRunInCurrentRunState(periodic))
cancel(false);
else if (!periodic)
ScheduledFutureTask.super.run();
else if (ScheduledFutureTask.super.runAndReset()) {
setNextRunTime();
reExecutePeriodic(outerTask);
}
}
As you can see it invokes actual task logic in runAndReset, calculates the next running time and submits the same updated task to the queue again (reExecutePeriodic is almost the same as schedule). There is only a single periodic task for all executions which is resubmitted again and again with updated time after the previous execution is finished. So such thread pool runs only a single instance of each task type in any given moment and scales only for different type of tasks.
If you are interesting in how spring schedules tasks take a look at ScheduledTaskRegistrar class and particularly at scheduleFixedDelayTask method.
In the case that you use threadpool:
By default you going to have 10 threads in your pool(already initialized). The first time that #scheduled is executed, this function is going to execute in a thread from your pool (now remaining 9 threads), if the function yet finished and #scheduled is executed again, your function going to executed in other thread from you your pool, so now you have 8 thread remaining in your pool. (8 idle, 2 running threads)
If you aren`t use threadpool only one thread is used.
spring documentation:
If you do not provide a 'pool-size' attribute, the default thread pool
will only have a single thread. There are no other configuration
options for the scheduler.
https://docs.spring.io/spring/docs/4.3.x/spring-framework-reference/html/scheduling.html

ScheduledExecutorService not behaving as expected

I'm trying to execute a task at midnight after a fixed amount of days using ScheduleExecutorService. My method runs inside of my tomcat 8 and looks like this:
public void schedule (int aInterval)
{
String timezone = TimeZone.getDefault().getID();
ZoneId z = ZoneId.of(timezone);
ZonedDateTime now = ZonedDateTime.now( z );
LocalDate tomorrow = now.toLocalDate().plusDays(1);
ZonedDateTime tomorrowStart = tomorrow.atStartOfDay( z );
Duration duration = Duration.between( now , tomorrowStart );
long millisecondsUntilTomorrow = duration.toMillis();
long interval;
if (aInterval * 24 * 60 * 60 > Long.MAX_VALUE)
{
interval = Long.MAX_VALUE;
}
else
{
interval = aInterval * 24 * 60 * 60;
}
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1, new ThreadFactory() {
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
// allow the JVM to kill the scheduled task
thread.setDaemon(true);
return thread;
});
scheduler.scheduleAtFixedRate(new Runnable()
{
public void run() {
System.out.println(String.format("schedule::run() at %1$Td.%1$tm.%1$tY %1$tH:%1$tM:%1$tS \n", System.currentTimeMillis() ) );
doTask();
}
},
delay,
interval,
TimeUnit.SECONDS);
}
Now when the method is first run it seems like is not executed as specifed by delay and interval. E.g. when i set delay=60 and interval=5 in my stacktrace it looks like this:
...
schedule::run() at 10.08.2017 17:57:09
schedule::run() at 10.08.2017 17:57:15
schedule::run() at 10.08.2017 17:57:21
schedule::run() at 10.08.2017 17:57:27
schedule::run() at 10.08.2017 17:57:27
schedule::run() at 10.08.2017 17:57:33
schedule::run() at 10.08.2017 17:57:33
schedule::run() at 10.08.2017 17:57:34
...
So the intervals somehow are becoming shorter and shorter over time. What is going on here? Is there a problem in my method?
Now when the method is first run it seems like is not executed as specified by delay and interval. E.g. when i set delay=60 and interval=5 in my stacktrace it looks like this...
I try to be very explicit with my time variables. In this case, you should be dealing with milliseconds so delayMillis, intervalMillis, aIntervalMillis, etc. should be in your code. If they are seconds then use delaySecs, etc. but you will need to multiple them by 1000 when you pass them to the scheduleAtFixedRate(...) method which is expecting millis.
So the intervals somehow are becoming shorter and shorter over time. What is going on here? Is there a problem in my method?
What's probably going on is that the task is trying to schedule it every 5 milliseconds so the random delays are just showing you how long your doTask() takes to run. If you want to set them to 60 and 5 seconds respectively then you should use 60000 and 5000 instead.
When i try that and my schedule() method is running i get a message from my eclipse (neon 3) saying tomcat is not responding and my tomcat is not shutting down properly.
Not sure about this but I suspect that your tomcat is waiting for your scheduled task to finish which is never will on its own. You could use a ThreadFactory and create a daemon thread instead which the JVM will not wait for when it shuts down. Note that if it is a daemon thread then it might get terminated right in the middle of running.
scheduler = Executors.newScheduledThreadPool(1, new ThreadFactory() {
public Thread newThread(Runnable r) {
Thread thread = new Thread(r);
// allow the JVM to kill the scheduled task
thread.setDaemon(true);
return thread;
}
});
Also, you should call scheduler.shutdown() on your thread-pool after you submit your fixed task. It will continue to run but no other jobs will be submitted. That's a good pattern.
How can I stop my execution task in a proper way?
The daemon thread mode about may be "proper" in your case but you can also cancel it. The scheduler.scheduleAtFixedRate(...) method returns a ScheduledFuture object that you can call cancel(...) on to stop it. Once your doTask() finishes it won't be scheduled again. You can also call cancel(true) on it to set the interrupt flag on the thread but your code is going to have to handle that specifically.
Of course you are going to need to detect that your JVM is shutting down so you can cancel your task. You could set a shutdown hook which is a bit of a hack. Maybe there is some way for tomcat to notify that it's coming down?
the intervals somehow are becoming shorter and shorter over time
We need to understand how ScheduledExecutorService:scheduleAtFixedRate is supposed to work. According to docs, https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ScheduledExecutorService.html#scheduleAtFixedRate, we can conclude the following:
The time of each run is pre-determined.
This pre-calculated time may not tally when the previous run of the same task takes longer than point no 1. In such case, the
next run will happen immediately after the longer running previous run
has finished.
Same task can never run concurrently; even if the expected start time of the next run has exceeded. As mentioned by point no 2, the next run will wait till
the previous longer run finishes.
Now, coming to your case, you had expected to see your task getting run at equal intervals. But, instead the intervals between them are getting shorter with each run. This could be due to any previous run that took considerable longer time, piling up other run(s) which have exceeded their expected start time. Further piled up runs (doTask method) finish quickly. So, all the piled up runs are running at closer intervals. If you really want the task to run at equal intervals, you could instead use ScheduledExecutorService: scheduleWithFixedDelay

ExecutorService how to change scheduling clock

I am using Java executorservice to create a timeout effect in one of my apps. After an elapsed time, they executor service begins and logs the user out of their session. But on an Android device when the device goes to sleep the executor thread is suspended. After the device awakes the thread is unsuspended. I would like the change the clock the executor is using so that it continues counting even after the device goes to deep sleep. Is there no way I can over ride which clock is being used (I realize I can swap out the entire implementation and use alarmmanager but I'm looking to not alter existing code at this point so please do not try to offer other APIs).
My question is, there must be a system clock that keeps going despite the device being asleep, how can I let the executor scheduler use that clock instead of the one it's using now which respects the device going to deep sleep and pauses ticking?
My code I have currently is very simple and just looks like this:
myExecutorService.schedule(new EndUserSession(),
6L, TimeUnit.MINUTES);
this code above starts the EndUserSession() in 6 minutes. It works but I want to use another clock that does not respect time out of mobile device.
I have strong doubts that it's possible to influence scheduler service timing mechanisms.
You have another option to avoid problems caused by device sleep, like passing specific timestamp in constructor and scheduling a task at fixed rate. Example:
class EndSessionTask {
final long sessionExpirationTime;
volatile ScheduledFuture future;
public EndSessionTask(long ts) { sessionExpirationTime = ts; }
public void run() {
if (sessionExpirationTime < currentTs) return;
endSession();
future.cancel();
}
public void setFuture(ScheduledFuture f) { this.future = f; }
}
long endSessionTime = System.currentTimeMillis() + 6 * 60 * 1000;
EndSessionTask task = new EndSessionTask(endSessionTime);
ScheduledFuture future = executorService.scheduleAtFixedRate(task, 10L, 10L, SECONDS);
task.setFuture(future);

how to schedule a task with start time and end time using java Timer and TimerTask

Hi im developing some schedular which should start at a particular time and it should stop after some time.. starting after a delay i can do using timer and timerTask classes.. But stopping i dont have much idea. How to stop the timer after a elapsed time.
If you run your task in a thread, you can keep a reference to the Future object of the task and set a timeout. Something like that :
Future<?> future = executor.submit(new customTask()));
try {
future .get(timeout, TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
// The timeout exception is thrown when the get times out. Handle your stop logic here
}
You might want to handle the InterruptedException, ExecutionException and TimeoutException separately.
You can also call the .cancel() method on the Future object when your stop timer expires, but I recall reading somewhere that it is not recommanded

The best way to scheduler a process on the first day every 2 months even the server was down

I have a simple task: I need to run a process on the first day every 2 months even the server was down
If the server will not down – the task is very easy:
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
CronTrigger trigger = new CronTrigger("0 0 1 1 */2 ?");
scheduler.schedule(new Runnable() {
#Override
public void run() {
// do the job
job();
}
}, trigger);
But what if the server was down and I run my job a month ago?
In this case I want to execute my job on the beginning of the next month.
I decided to store in the database when I executed the job last time:
private void job() {
// Store when the job was executed the last time
}
Now, when my server is launched, I need to start the trigger once again, but not immediately.
I can easily calculate when I want to start the trigger, but unfortunately I can not find the appropriate function in ThreadPoolTaskScheduler. There is function that will allow to run task at start time periodically:
public ScheduledFuture scheduleAtFixedRate(Runnable task, Date startTime, long period)
Unfortunately, ThreadPoolTaskScheduler does not support
public ScheduledFuture schedule(Runnable task, Date startTime, Trigger trigger)
I implemented the functionality using additional scheduler.execute, but the question if it possible to do it using one schedule.
You could use java.util.Timer to do that, and schdule the next TimerTask inside your TimerTask implementation.
If it has to be exactly two months you should schedule another TimerTask when the TimerTask starts, otherwise you could schedule it when the TimerTask ends.

Categories