7

The TimeUnit.sleep(long timeout) documentation describes its argument thus:

timeout - the minimum time to sleep.

However, I'm finding that — at least on Windows 7 64-bit with Java 8 update 141 — the thread often sleeps for less than the minimum:

public static void main(String[] args) throws InterruptedException {
    final long from = TimeUnit.MILLISECONDS.toNanos(100);
    final long to   = TimeUnit.MILLISECONDS.toNanos(1000);
    final long step = TimeUnit.MILLISECONDS.toNanos(100);
    for (long requestedSleepDuration = from; requestedSleepDuration < to; requestedSleepDuration += step) {
        long sleepStartTime = System.nanoTime();
        TimeUnit.NANOSECONDS.sleep(requestedSleepDuration);
        long sleepEndTime = System.nanoTime();
        System.out.printf(
                "requested=%9d  actual=%9d  %s%n",
                requestedSleepDuration,
                sleepEndTime - sleepStartTime,
                (sleepEndTime - sleepStartTime >= requestedSleepDuration ? "OK" : " Slept less than minimum!"));
    }
}

Typical output:

requested=100000000  actual= 99534864  Slept less than minimum!
requested=200000000  actual=200063646  OK
requested=300000000  actual=299223086  Slept less than minimum!
requested=400000000  actual=399598620  Slept less than minimum!
requested=500000000  actual=499910360  Slept less than minimum!
requested=600000000  actual=600028523  OK
requested=700000000  actual=699604816  Slept less than minimum!
requested=800000000  actual=799230602  Slept less than minimum!
requested=900000000  actual=899490648  Slept less than minimum!

This seems to contradict the documentation. However, the TimeUnit doc also states that TimeUnit.sleep() is a convenience wrapper for Thread.sleep, and the latter doesn't say if it guarantees to sleep at least the specified amount.

Is this an API implementation error, or is TimeUnit.sleep and/or Thread.sleep designed to only sleep for approximately, rather than at least, the specified duration?

Klitos Kyriacou
  • 10,634
  • 2
  • 38
  • 70
  • I always thought they were approximate, not guaranteed – blurfus Jul 31 '17 at 15:34
  • The system clock typically has a resolution of 15ms. Why are you trying to sleep in nanoseconds? – Elliott Frisch Jul 31 '17 at 15:45
  • @ElliottFrisch I'm not trying to sleep in nanoseconds, and I'm not trying to be exact, but would like to sleep for *at least* the required time. A little more is ok. I'm only using nanoseconds because Java's monotonic clock is `System.nanoTime()` - there's no alternative unit. `System.currentTimeMillis()` is unsuitable as it's subject to clock adjustments. – Klitos Kyriacou Jul 31 '17 at 15:48
  • Man. I typed out a reasonably long answer and now I can't post it. Can someone vote to reopen? – Michael Jul 31 '17 at 15:54
  • @Michael my apologies, I marked the question suggested in the duplicate notice as "This answers my question" and that marked my question as a duplicate. I now can't undo it. I voted to reopen, but this requires 4 votes. 2 so far, 2 more needed to reopen. I don't like the way SO works. – Klitos Kyriacou Jul 31 '17 at 16:02
  • 1
    Yep, it's rubbish. I just posted a similar (though slightly different) question [and answered it myself](https://stackoverflow.com/questions/45420662/how-can-i-guarantee-that-thread-sleep-sleeps-for-at-least-a-minimum-amount-of-ti/) in case you're interested. – Michael Jul 31 '17 at 16:13
  • @KlitosKyriacou SO questions aren't like forum discussion threads. You don't reopen an answered question to ask a different follow-up question, you just post it as a new question, so people with that specific question can find it. – Sean Van Gorder Jul 31 '17 at 16:34

1 Answers1

4

TimeUnit.sleep() delegates to Thread.sleep().

Thread.sleep() is subject to the precision and accuracy of system timers and schedulers, thus TimeUnit.sleep() will not be as accurate as you may need.

UserF40
  • 3,533
  • 2
  • 23
  • 34