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:
- there is also a bug in Windows whereby repeatedly altering the interrupt period (and
hence, repeatedly sleeping in Java for periods that are not multiples of 10ms) can make the
system clock run fast;
- Hotspot assumes that the default interrupt period is 10ms, but on some hardware it is 15ms.
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) {
Thread.sleep(millisLeft);
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.
Did this article solve your problem? If not, you can now
post a comment or question
Java threading articles
Java threading and concurrency
Java profiling
Java performance graph index
Unless otherwise stated, the Java programming articles and tutorials on this site are written by Neil Coffey.
Suggestions are always welcome if you wish to suggest topics for Java tutorials or programming articles,
or if you simply have a programming question that you would like to see answered on this site. Most topics
will be considered. But in particular, the site aims to provide tutorials and information on topics that
aren't well covered elsewhere, or on Java performance information that is poorly described or understood.
Suggestions may be made via the Javamex blog (see the site's front page for details).
Copyright © Javamex UK 2011. All rights reserved.