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()):
The second chart shows 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);
}