yield(), sleep(0), wait(0,1) and parkNanos(1)

Overview

On the surface these methods do the same thing in Java; Thread.yield(), Thread.sleep(0), Object.wait(0,1) and LockSupport.parkNanos(1)

They all wait a sort period of time, but how much that is varies a surprising amount and between platforms.

Timing a short delay

The following code times how long it takes to repeatedly call those methods.
import java.util.concurrent.locks.LockSupport;

public class Pausing {
    public static void main(String... args) throws InterruptedException {
        int repeat = 10000;
        for (int i = 0; i < 3; i++) {
            long time0 = System.nanoTime();
            for (int j = 0; j < repeat; j++)
                Thread.yield();
            long time1 = System.nanoTime();
            for (int j = 0; j < repeat; j++)
                Thread.sleep(0);
            long time2 = System.nanoTime();
            synchronized (Thread.class) {
                for (int j = 0; j < repeat/10; j++)
                    Thread.class.wait(0, 1);
            }
            long time3 = System.nanoTime();
            for (int j = 0; j < repeat/10; j++)
                LockSupport.parkNanos(1);
            long time4 = System.nanoTime();

            System.out.printf("The average time to yield %.1f μs, sleep(0) %.1f μs, " +
                    "wait(0,1) %.1f μs and LockSupport.parkNanos(1) %.1f μs%n",
                    (time1 - time0) / repeat / 1e3, (time2 - time1) / repeat / 1e3, 
                    (time3 - time2) / (repeat/10) / 1e3, (time4 - time3) / (repeat/10) / 1e3);
        }
    }
}

On Windows 7

The average time to yield 0.3 μs, sleep(0) 0.6 μs, wait(0,1) 999.9 μs and LockSupport.parkNanos(1) 1000.0 μs
The average time to yield 0.3 μs, sleep(0) 0.6 μs, wait(0,1) 999.5 μs and LockSupport.parkNanos(1) 1000.1 μs
The average time to yield 0.2 μs, sleep(0) 0.5 μs, wait(0,1) 1000.0 μs and LockSupport.parkNanos(1) 1000.1 μs

On RHEL 5.x

The average time to yield 1.1 μs, sleep(0) 1.1 μs, wait(0,1) 2003.8 μs and LockSupport.parkNanos(1) 3.8 μs
The average time to yield 1.1 μs, sleep(0) 1.1 μs, wait(0,1) 2004.8 μs and LockSupport.parkNanos(1) 3.4 μs
The average time to yield 1.1 μs, sleep(0) 1.1 μs, wait(0,1) 2005.6 μs and LockSupport.parkNanos(1) 3.1 μs

On Ubuntu 11.x

The average time to yield 0.4 μs, sleep(0) 0.4 μs, wait(0,1) 1084.8 μs and LockSupport.parkNanos(1) 53.9 μs
The average time to yield 0.2 μs, sleep(0) 0.3 μs, wait(0,1) 1104.8 μs and LockSupport.parkNanos(1) 53.1 μs
The average time to yield 0.3 μs, sleep(0) 0.3 μs, wait(0,1) 1088.2 μs and LockSupport.parkNanos(1) 52.4 μs

In summary

If you want to wait for a short period of time, you can't assume that all these methods do the same thing, nor will be the same between platforms.

Comments

  1. Thanks for the great article! Any suggestions what is causing this? The JVM version, the kernel version, ..?

    ReplyDelete
  2. In the case of wait(0, 1), the Java code makes it the same of wait(1) i.e. wait for millisecond rather than a nano-second.

    I believe the other delays are OS dependant.

    ReplyDelete
  3. On Windows 7 with -server turned on call of wait(0, 1) took ~15000 μs:
    https://github.com/plokhotnyuk/actors/blob/0a5f3c9d753cbdce95fcae38f7341b183a0ad586/out1.txt#L233

    ReplyDelete
  4. You need to be wary that Object.wait() must happen in a monitor that gets inflated. This can be quite costly on the JVM to collect.

    ReplyDelete
    Replies
    1. Doesn't parkNanos also use monitor+condition under the hood?

      Delete
  5. Hello Peter. Apologies: I am terribly late to reply. I only found this post yesterday. It is excellent.

    I am curious about the results of this loop (as it may give us some indication of the cost of acquiring an uncontested monitor/lock on Thread.class):

    for (int j = 0; j < repeat/10; j++)
    synchronized (Thread.class) {
    Thread.class.wait(0, 1);
    }
    long time3b = System.nanoTime();

    ReplyDelete

Post a Comment

Popular posts from this blog

Java is Very Fast, If You Don’t Create Many Objects

Low Latency Microservices, A Retrospective

Unusual Java: StackTrace Extends Throwable