-
Enhancement
-
Resolution: Unresolved
-
P4
-
None
-
17
-
generic
-
generic
A DESCRIPTION OF THE PROBLEM :
Currently it is not specified how ScheduledExecutorService and ScheduledThreadPoolExecutor, especially their `scheduleAtFixedRate` methods, handle a negative `initialDelay` value (might also be relevant for `scheduleWithFixedDelay`). The following two important questions are left unanswered:
1. Will the task run immediately?
2. If the task runs immediately, will the second run then have a shorter delay to make sure it still runs at the desired point in time, or will `period` be calculated based on the time when the task was scheduled instead?
As use case let's imagine some background task which should run at 10:00 o'clock every day, and the code scheduling it calculates `initialDelay = desiredStartTime - currentTime`, so the result might be negative if it is already past 10:00 o'clock.
The actual behavior of ScheduledThreadPoolExecutor for negative initial delay values seems to be (1) the task is run immediately and (2) the `period` is added to the current time instead of the initial delay (this could be considered a contraction to the `initialDelay + period`, ... mentioned in the documentation).
For the background task example above this means if the task, which is supposed to run at 10:00 o'clock every day, is scheduled at 11:37 o'clock, then it will run at 11:37 o'clock every day instead.
Below is a small example demonstrating that instead of printing "00", "10", "20", ... it prints the seconds of whatever the current time is + n * 10, e.g. "07", "17, "27", ....
===============
import java.time.LocalTime;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
class SchedulingTest {
public static void main(String[] args) {
ZonedDateTime startDateTime = ZonedDateTime.now().withSecond(0);
long startDelay = startDateTime.toInstant().toEpochMilli() - System.currentTimeMillis();
ScheduledExecutorService executor = new ScheduledThreadPoolExecutor(1);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("ss");
executor.scheduleAtFixedRate(
() -> System.out.println(formatter.format(LocalTime.now())),
startDelay,
TimeUnit.SECONDS.toMillis(10),
TimeUnit.MILLISECONDS
);
}
}
Currently it is not specified how ScheduledExecutorService and ScheduledThreadPoolExecutor, especially their `scheduleAtFixedRate` methods, handle a negative `initialDelay` value (might also be relevant for `scheduleWithFixedDelay`). The following two important questions are left unanswered:
1. Will the task run immediately?
2. If the task runs immediately, will the second run then have a shorter delay to make sure it still runs at the desired point in time, or will `period` be calculated based on the time when the task was scheduled instead?
As use case let's imagine some background task which should run at 10:00 o'clock every day, and the code scheduling it calculates `initialDelay = desiredStartTime - currentTime`, so the result might be negative if it is already past 10:00 o'clock.
The actual behavior of ScheduledThreadPoolExecutor for negative initial delay values seems to be (1) the task is run immediately and (2) the `period` is added to the current time instead of the initial delay (this could be considered a contraction to the `initialDelay + period`, ... mentioned in the documentation).
For the background task example above this means if the task, which is supposed to run at 10:00 o'clock every day, is scheduled at 11:37 o'clock, then it will run at 11:37 o'clock every day instead.
Below is a small example demonstrating that instead of printing "00", "10", "20", ... it prints the seconds of whatever the current time is + n * 10, e.g. "07", "17, "27", ....
===============
import java.time.LocalTime;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
class SchedulingTest {
public static void main(String[] args) {
ZonedDateTime startDateTime = ZonedDateTime.now().withSecond(0);
long startDelay = startDateTime.toInstant().toEpochMilli() - System.currentTimeMillis();
ScheduledExecutorService executor = new ScheduledThreadPoolExecutor(1);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("ss");
executor.scheduleAtFixedRate(
() -> System.out.println(formatter.format(LocalTime.now())),
startDelay,
TimeUnit.SECONDS.toMillis(10),
TimeUnit.MILLISECONDS
);
}
}