FULL PRODUCT VERSION :
java version "1.8.0_45"
Java(TM) SE Runtime Environment (build 1.8.0_45-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.45-b02, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Darwin Macintosh-2.local 13.4.0 Darwin Kernel Version 13.4.0: Sun Aug 17 19:50:11 PDT 2014; root:xnu-2422.115.4~1/RELEASE_X86_64 x86_64
A DESCRIPTION OF THE PROBLEM :
Scheduling a fixed delay task with a delay of Long.MAX_VALUE always causes a previously scheduled task to never run *IF* the fixed delay task is running at the time the previously scheduled task becomes eligible to run.
The following method can be used to illustrate the problem:
public void runSchedulingScenario(long delayInMillis) throws InterruptedException {
System.out.println("Running scenario for delay of " + delayInMillis);
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
// schedule task to run in 1 second
scheduledExecutorService.schedule(() -> {
System.out.println("scheduled task with one second delay invoked");
}, 1, TimeUnit.SECONDS);
// schedule task to run immediately and then not again for specified delay
// NOTE that task runs for ~two seconds and so is actively running at the
// point the first scheduled task would be eligible for execution
scheduledExecutorService.scheduleWithFixedDelay(() -> {
try {
System.out.println("scheduled task with fixed delay invoked");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, 0, delayInMillis, TimeUnit.MILLISECONDS);
System.out.println("scheduling completed");
Thread.sleep(10000);
}
As seen above, the method first schedules a delayed task to execute in 1 second and then schedules a "fixed delay" task for immediate execution with the specified delay.
The expectation is that the "fixed delay" task will execute immediately, that the task that was scheduled to execute in 1 second will become eligible to run while the "fixed delay" task is actively running, and that the task that was scheduled to execute in 1 second will execute immediately upon completion of the "fixed delay" task.
Output from runSchedulingScenario(Integer.MAX_VALUE); is as expected:
Running scenario for delay of 2147483647
scheduling completed
scheduled task with fixed delay invoked
scheduled task with one second delay invoked
Unexpectedly, if Long.MAX_VALUE is used as the delay, the scheduled task with one second delay is never invoked as seen from the output of runSchedulingScenario(Long.MAX_VALUE);
Running scenario for delay of 9223372036854775807
scheduling completed
scheduled task with fixed delay invoked
Additional Notes:
1. some delay values less than Long.MAX_VALUE (eg Long.MAX_VALUE/2) also exhibit this problem
2. some delay values greater than Integer.MAX_VALUE (eg 157784630000L) do NOT exhibit this problem
3. if the code above is modified to remove the Thread.sleep(2000) step, then the problem never occurs
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
invoke the following method using an argument of Long.MAX_VALUE
public void runSchedulingScenario(long delayInMillis) throws InterruptedException {
System.out.println("Running scenario for delay of " + delayInMillis);
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
// schedule task to run in 1 second
scheduledExecutorService.schedule(() -> {
System.out.println("scheduled task with one second delay invoked");
}, 1, TimeUnit.SECONDS);
// schedule task to run immediately and then not again for specified delay
// NOTE that task runs for ~two seconds and so is actively running at the
// point the first scheduled task would be eligible for execution
scheduledExecutorService.scheduleWithFixedDelay(() -> {
try {
System.out.println("scheduled task with fixed delay invoked");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, 0, delayInMillis, TimeUnit.MILLISECONDS);
System.out.println("scheduling completed");
Thread.sleep(10000);
}
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Running scenario for delay of 9223372036854775807
scheduling completed
scheduled task with fixed delay invoked
scheduled task with one second delay invoked
ACTUAL -
Running scenario for delay of 9223372036854775807
scheduling completed
scheduled task with fixed delay invoked
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ScheduledThreadPoolExecutorTest {
public static void main(String[] args) {
try {
runSchedulingScenario(Long.MAX_VALUE);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void runSchedulingScenario(long delayInMillis) throws InterruptedException {
System.out.println("Running scenario for delay of " + delayInMillis);
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);
// schedule task to run in 1 second
scheduledExecutorService.schedule(() -> {
System.out.println("scheduled task with one second delay invoked");
}, 1, TimeUnit.SECONDS);
// schedule task to run immediately and then not again for specified delay
// NOTE that task runs for ~two seconds and so is actively running at the
// point the first scheduled task would be eligible for execution
scheduledExecutorService.scheduleWithFixedDelay(() -> {
try {
System.out.println("scheduled task with fixed delay invoked");
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}, 0, delayInMillis, TimeUnit.MILLISECONDS);
System.out.println("scheduling completed");
Thread.sleep(10000);
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
For the extremely rare cases where you are forced to schedule a task to run with a very long delay, using a large value like 157784630000L (5 years) is sufficient.