Bugs and issues with Thread.sleep()

Having seen the general behaviour of Thread.sleep in Java, there are a few issues that we should be aware of.

Bugs with Thread.sleep() under Windows

As mentioned, to try and alleviate the low granularity, the VM actually makes a special call to set the interrupt period to 1ms while any Java thread is sleeping, if it requests a sleep interval that is not a multiple of 10ms. This means you are actually make a system-wide change to interrupt behaviour (although generally not such a problem). Generally, the solution works well enough, but:

If timing is crucial to your application, then an inelegant but practical way to get round these bugs is to leave a daemon thread running throughout the duration of your application that simply sleeps for a large prime number of milliseconds (Long.MAX_VALUE will do). This way, the interrupt period will be set once per invocation of your application, minimising the effect on the system clock, and setting the sleep granularity to 1ms even where the default interrupt period isn't 15ms.

"Guaranteeing" a certain sleep time

For reasons we'll discuss in the section How does sleep work?, there is no guarantee as to how long the thread will actually sleep: this can depend on factors such as what other threads are competing for the CPU, and on the sleep granularity that a given OS can fulfil.

The next-best solution is usually to time the sleep, and then make some adjustment depending on how long the thread actually slept for. For example, to sleep for at least a given amount of time, we can call sleep in a loop until the total amount of time slept for reaches at least the required number of milliseconds:

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

In an animation thread or similar case where we want spaces between sleeps to be as even as possible, a common solution is to adjust the next sleep to compensate for undersleeping/oversleeping (or, put another way, calculate how many milliseconds there are between now and the next expected time for the task to be performed, and sleep for that many milliseconds). The java.util.Timer class effectively provides an implementation of this approach.

Scheduling with oversleepy threads

A pragmatic observation illustrated in Figure 1 is that if anything, threads will tend to oversleep rather than undersleep. This means that if you're using Thread.sleep() to schedule something like a MIDI interface that can itself accept a small delay on events sent to it, it may better to deliberately request a lower-than-needed sleep duration, and then pass on the amount of undersleep (within some maximum) to the MIDI device. For example, suppose we need to send a MIDI note in 40 milliseconds' time. So we call Thread.sleep() with a value of 30ms but time that the actual sleep was 35ms. At that point, even though the note isn't due for another 5ms, a busy system may not be able to guarantee returning to our thread within 5ms (or timing within this granularity). So we send the note early, but ask the MIDI interface to delay the note by 5ms. The MIDI interface may or may not be able to honour this delay, but the overall timing error is unlikely to be worse than if we'd asked to sleep the full 40ms and risked sending the note late.