Home > database >  Why Thread.sleep(long mills, int nanos) and Object.wait(long mills, int nanos) actually ignore nanos
Why Thread.sleep(long mills, int nanos) and Object.wait(long mills, int nanos) actually ignore nanos

Time:07-14

I am using JDK 17 on macOS. I looked into Thread.sleep(long mills, int nanos) and Object.wait(long mills, int nanos) and their source code as follows:

Thread.sleep:

    public static void sleep(long millis, int nanos)
    throws InterruptedException {
        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (nanos < 0 || nanos > 999999) {
            throw new IllegalArgumentException(
                                "nanosecond timeout value out of range");
        }

        if (nanos > 0 && millis < Long.MAX_VALUE) {
            millis  ;
        }

        sleep(millis);
    }

Object.wait:

    public final void wait(long timeoutMillis, int nanos) throws InterruptedException {
        if (timeoutMillis < 0) {
            throw new IllegalArgumentException("timeoutMillis value is negative");
        }

        if (nanos < 0 || nanos > 999999) {
            throw new IllegalArgumentException(
                                "nanosecond timeout value out of range");
        }

        if (nanos > 0 && timeoutMillis < Long.MAX_VALUE) {
            timeoutMillis  ;
        }

        wait(timeoutMillis);
    }

So according to code nanos amount is actually ignored -if it is more than zero, then mills will just increment. Why is that? Is it because my system does not support nanos resolution?

CodePudding user response:

Per the javadoc of System#nanoTime:

This method provides nanosecond precision, but not necessarily nanosecond resolution (that is, how frequently the value changes) - no guarantees are made except that the resolution is at least as good as that of currentTimeMillis()

All of this to say is that while System#nanoTime will provide you a time in nanoseconds, it will not necessarily be an accurate time. Rather, the time will only be as accurate as System#currentTimeMillis. Due to this, there has been a history of System#nanoTime occasionally returning erroneous values on successive calls (such as returning a lower value than a previous result).

To that end, it is simpler to increment the number of required milliseconds to ensure that the duration waited surpasses the number of desired nanoseconds, rather than to actually check against System#nanoTime.

It is also noted within the javadoc for Object#wait:

nanos - additional time, in nanoseconds range 0-999999.

and Thread#sleep:

nanos - 0-999999 additional nanoseconds to sleep

Such that the number of nanoseconds cannot exceed an additional millisecond, allowing them to simply increment the milliseconds by 1 in the event additional nanoseconds must be waited for.

CodePudding user response:

Use LockSupport.parkNanos instead. Under Linux this will give you 50us resolution. https://hazelcast.com/blog/locksupport-parknanos-under-the-hood-and-the-curious-case-of-parking/

  • Related