Andy Malakov software blog

Sunday, June 6, 2010

Alternative to Thread.sleep()

Follow-up to my previous post. Here is an alternative to Thread.sleep() that uses spin-yield:

private static final long SLEEP_PRECISION = TimeUnit.MILLISECONDS.toNanos(2); //TODO: Determine for current machine

public static void sleepNanos (long nanoDuration) throws InterruptedException {
final long end = System.nanoTime() + nanoDuration;


long timeLeft = nanoDuration;
do {
if (timeLeft > SLEEP_PRECISION)
Thread.sleep (
1);
else

Thread.sleep (
0); // Thread.yield();
timeLeft = end - System.nanoTime();

if (Thread.interrupted())
throw new InterruptedException ();

}
while (timeLeft > 0);

}



Test


I run 4 threads requesting 5 millisecond sleep 1000 times each (on my Dual-Core CPU). The first chart shows sleepNanos(TimeUnit.MILLISECONDS(5).toNanos()):

Actual sleep time of sleepNanos(5000000)

The second chart shows Thread.sleep(5):

Actual sleep time of Thread.sleep(5)

As you can see, sleepNanos() is much more precise. I found that this approach was originally used by Ryan Geiss for WinAmp visualization plugin.

UPDATE



Even better precision can be achieved if you are willing to consume more CPU power doing Spin-Wait for the last part of the wait:







public static void sleepNanos (long nanoDuration) throws InterruptedException {
final long end = System.nanoTime() + nanoDuration;
long timeLeft = nanoDuration;
do {

if (timeLeft > SLEEP_PRECISION)
Thread.sleep (1);
else
if (timeLeft > SPIN_YIELD_PRECISION)

Thread.sleep(0);

timeLeft = end - System.nanoTime();

if (Thread.interrupted())
throw new InterruptedException ();

} while (timeLeft > 0);

}