FULL PRODUCT VERSION :
java -version
java version "1.7.0_07"
Java(TM) SE Runtime Environment (build 1.7.0_07-b10)
Java HotSpot(TM) Client VM (build 23.3-b01, mixed mode, sharing)
A DESCRIPTION OF THE PROBLEM :
When ScheduledExecutorService.scheduleWithFixedDelay is called with a delay of Long.MAX_VALUE and a TimeUnit longer than NANOSECONDS it fails badly, putting the executor service into an unusable state.
The problem is due to the internal storage of the delay as a negative number in the "period" field of the ScheduledFutureTask (positive numbers mean fixed-rate rather than fixed-delay). The period field is set to TimeUnit.toNanos(-delay), and if the delay is large enough and the TimeUnit is longer than NANOSECONDS then this will be equal to Long.MIN_VALUE. Later, when the period field is used in .ScheduledThreadPoolExecutor.ScheduledFutureTask.setNextRunTime() it is converted back to a positive number with the unary minus operator before being passed to the triggerTime method. However, -Long.MIN_VALUE is a negative number (since the magnitude of Long.MIN_VALUE is one greater than the magnitude of Long.MAX_VALUE)! This results in triggerTime returning a time in the distant past.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ScheduledTaskBug
{
static public void main(String[] args) throws InterruptedException
{
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
executor.scheduleWithFixedDelay(new Runnable()
{
@Override
public void run()
{
System.out.println("running scheduled task with delay: " + new Date());
}
}, 0, Long.MAX_VALUE, TimeUnit.MICROSECONDS);
// This second task should run right after the first run of the previously task scheduled
// with a delay.
// However, due to a bug in scheduleWithFixedDelay, it never runs. If the TimeUnit above is
// changed to TimeUnit.NANOSECONDS then the following task will run as expected.
executor.submit(new Runnable()
{
@Override
public void run()
{
System.out.println("running immediate task: " + new Date());
}
});
Thread.sleep(5000);
executor.shutdownNow();
}
}
---------- END SOURCE ----------