9

As per this question, Thread.sleep is not necessarily guaranteed to sleep for the duration you specify: it may be shorter or longer.

If you read the documentation for Thread.sleep, you'll see there are no strong guarantees over the exact duration which will be slept. It specifically states the duration is

subject to the precision and accuracy of system timers and schedulers

which is (intentionally) vague but hints that the duration should not be relied upon too heavily.

The granularity of possible sleep durations on a particular operating system is determined by the thread scheduler's interrupt period.

In Windows, the scheduler's interrupt period is normally around 10 or 15 milliseconds (which I believe is dictated by the processor), but a higher period can be requested in software and the Hotspot JVM does so when it deems necessary

Source, emphasis mine

How can I practically guarantee that the sleep duration will be at least the value that I specify?

Michael
  • 41,989
  • 11
  • 82
  • 128
  • What is your use case for making the thread sleep x time? Are you just scheduling? If so there are better ways to do this – UserF40 Jul 31 '17 at 16:19
  • 5
    @UserF40 one application I had in mind is throttling requests (or other types of event) to say, a maximum of N events per second. If you are about to make the Nth request and the 1st request was made less than a second ago, you need to wait *at least* the required amount of time before you make the request. – Klitos Kyriacou Jul 31 '17 at 16:22
  • @UserF40 I don't personally have a use case (if you look at the comments of the linked question you'll see why I asked this ;) ) but what Klitos mentioned seems reasonable. – Michael Jul 31 '17 at 16:26

1 Answers1

9

The best practical solution is to time the sleep and continue to sleep while there is time remaining:

public void sleepAtLeast(long millis) throws InterruptedException
{
    long t0 = System.currentTimeMillis();
    long millisLeft = millis;
    while (millisLeft > 0) {
       Thread.sleep(millisLeft);
       long t1 = System.currentTimeMillis();
       millisLeft = millis - (t1 - t0);
    }
}

Code and info is from here

Michael
  • 41,989
  • 11
  • 82
  • 128
  • 4
    Good solution but I would advise against using `currentTimeMillis`. If the user adjusts the system time (or you use an NTP service) while your Java application is running, this method will behave incorrectly. Use `System.nanoTime()` instead. – Klitos Kyriacou Jul 31 '17 at 16:26