Are Thread.sleep(0) and Thread.yield() statements equivalent?

JavaMultithreading

Java Problem Overview


Are these two statement equivalent?

Thread.sleep(0);
Thread.yield();

Java Solutions


Solution 1 - Java

No. The most obvious difference is that sleep() throws the (checked) InterruptedException. In practice, the effect may be almost the same, but it's entirely implementation-dependant.

I'd wager that doing each a million times in a row would take much longer for sleep(), since system timer granularity probably often causes it to actually sleep for a non-negligible amount of time.

Solution 2 - Java

Yield adds the current thread to the ready queue and allows other threads to run. Sleep is not guaranteed to relinquish the cpu.

Solution 3 - Java

This really depends on the platform and version of the JVM. For example, under Windows in JDK 5 (Hotspot), yield() is literally implemented as Sleep(0)-- although a sleep of 0 is treated slightly specially by Windows as I recall. But in JDK 6, yield() is implemented as SwitchToThread().

I put together some information a while ago on Thread.yield(), including some implementational details that may be of interest. (You might also want to see the stuff on Thread.sleep() I put together on the same site.)

Solution 4 - Java

OpenJDK source (Java SE 7) have the following implementation for Thread.sleep(0) in JVM_Sleep function of jvm.cpp:

  if (millis == 0) {
    // When ConvertSleepToYield is on, this matches the classic VM implementation of
    // JVM_Sleep. Critical for similar threading behaviour (Win32)
    // It appears that in certain GUI contexts, it may be beneficial to do a short sleep
    // for SOLARIS
    if (ConvertSleepToYield) {
      os::yield();
    } else {
      ThreadState old_state = thread->osthread()->get_state();
      thread->osthread()->set_state(SLEEPING);
      os::sleep(thread, MinSleepInterval, false);
      thread->osthread()->set_state(old_state);
    }
  }

And implemtation of Thread.yield() have the following code:

  // When ConvertYieldToSleep is off (default), this matches the classic VM use of yield.
  // Critical for similar threading behaviour
  if (ConvertYieldToSleep) {
    os::sleep(thread, MinSleepInterval, false);
  } else {
    os::yield();
  }

So Thread.sleep(0) and Thread.yield() may call same system calls in some platforms.

os::sleep and os::yield are platform specific stuff. On both Linux and Windows: os::yield seems to be much simplier than os::sleep. For example: os::yield of Linux calls only sched_yield(). And os::sleep have about 70 lines of code.

Solution 5 - Java

> yield() tells the JVM Thread Scheduler > that it's OK to give other threads > time slices. Usually the JVM uses this > call to activate another thread of the > same thread priority. In a good > preemptive multithreading environment, > yield() is a no-op. However, it is > important in a cooperative > multithreading environment, since > without yield(), one thread can eat up > all of the CPU. > > sleep(x) tells the JVM Thread > Scheduler to actively put this thread > to sleep and not run it again until at > least x milliseconds have elapsed. > > Neither sleep() nor yield() change > anything about the status of > synchronization locks. If your thread > has a lock, and you call sleep(1000), > then at least a second will elapse > before your thread wakes up. When it > wakes up it may decide to release the > lock -- or it may hold on to it > longer.

SOURCE: http://www.jguru.com/faq/view.jsp?EID=425624

Solution 6 - Java

The famous Brian Goetz's book "Java Concurrency in Practice" (published in 2006 but still fundamentally valid) says the following on this question.

> The semantics of Thread.yield and Thread.sleep(0) are undefined [JLS17.9]; the JVM is free to implement them as no-ops or treat them as scheduling hints. In particular, they are not required to have the semantics of sleep(0) on Unix systems — put the current thread at the end of the run queue for that priority, yielding to other threads of the same priority — though some JVMs implement yield in this way.

The rest one can find in the Javadoc pages.

Solution 7 - Java

Thread.Yield can give up CPU resource to threads with lower priorities, while Thread.Sleep(0) gives up CPU only to threads with equal or higher priorities.

At least on Windows platform :)

Solution 8 - Java

Thread.Sleep() has a slightly larger overhead because it creates a system that includes some kind of timer that will wake the process. (Depends on implementation basically)
Bottom line it will call a Yield() in the end.

Thread.Yield() Will just give-up the thread's turn, and gain it in the next round.

Thread.Sleep(0) might have an optimization to just call yield. (Again, implementation)

Solution 9 - Java

> What yield() is supposed to do is make the currently running thread > head back to runnable to allow other threads of the same priority to > get their turn. So the intention is to use yield() to promote graceful > turn-taking among equal-priority threads. In reality, though, the > yield() method isn't guaranteed to do what it claims, and even if > yield() does cause a thread to step out of running and back to > runnable, there's no guarantee the yielding thread won't just be > chosen again over all the others! So while yield() might—and often > does—make a running thread give up its slot to another runnable thread > of the same priority, there's no guarantee. > > A yield() won't ever cause a thread to go to the waiting/sleeping/ > blocking state. At most, a yield() will cause a thread to go from > running to runnable, but again, it might have no effect at all.

Source: SCJP Sun Certified Programmer book

Solution 10 - Java

Thread.sleep() and Thread.yield() do the same thing except that Thread.yield() relinquishes only to threads running on the same processor in multiprocessor environment.

Solution 11 - Java

It's platform-and-implementation-dependent, and they are likely not equivalent.

The below snippet, when using Thread.sleep(0), most of the time gives the output:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Whereas when using Thread.yield(), mostly gives:

[0, 1, 1, 1, 1, 1, 1, 1, 1, 1]
[0, 2, 2, 2, 2, 2, 2, 2, 2, 2]

See snippet below:

public class CompareSleepZeroAndYield {
    private ArrayList<Integer> list1 = new ArrayList<>();
    private ArrayList<Integer> list2 = new ArrayList<>();

    public ArrayList<Integer> getList1() {
        return list1;
    }

    public ArrayList<Integer> getList2() {
        return list2;
    }

    public CompareSleepZeroAndYield() {
        list1.add(0);
        list2.add(0);
    }

    public void tryFieldLock1() {
        synchronized (this.list1) {
            list1.add(list2.get(list2.size() - 1) + 1);
        }
    }

    public void tryFieldLock2() {
        synchronized (this.list2) {
            list2.add(list1.get(list1.size() - 1) + 1);
        }
    }

    public static void main(String[] args) {
        CompareSleepZeroAndYield obj = new CompareSleepZeroAndYield();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                int count = 10;
                while (--count >0) {
                    obj.tryFieldLock1();
                    try {
                        Thread.sleep(0);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    // compare above and below
                    // Thread.yield()
                }
                System.out.println(obj.getList1());
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                int count = 10;
                while (--count >0) {
                    obj.tryFieldLock2();

                    try {
                        Thread.sleep(0);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    // compare above and below
                    // Thread.yield()
                }
                System.out.println(obj.getList2());
            }
        });
        t1.start();
        t2.start();
}

Solution 12 - Java

No, they are not equivalent and besides the explanations above, I think it's necessary to check the Javadoc of yield. It seems not a good idea to use yield unless below situation meets.

> It is rarely appropriate to use this method. It may be useful > for debugging or testing purposes, where it may help to reproduce > bugs due to race conditions. It may also be useful when designing > concurrency control constructs such as the ones in the > {@link java.util.concurrent.locks} package.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPradyView Question on Stackoverflow
Solution 1 - JavaMichael BorgwardtView Answer on Stackoverflow
Solution 2 - Javaz -View Answer on Stackoverflow
Solution 3 - JavaNeil CoffeyView Answer on Stackoverflow
Solution 4 - JavaSKiView Answer on Stackoverflow
Solution 5 - JavaRoberto AloiView Answer on Stackoverflow
Solution 6 - Javapeter.petrovView Answer on Stackoverflow
Solution 7 - JavaVitaliy LiptchinskyView Answer on Stackoverflow
Solution 8 - JavaYochai TimmerView Answer on Stackoverflow
Solution 9 - JavaGrigor NazaryanView Answer on Stackoverflow
Solution 10 - JavaAbdulrahman AwwadView Answer on Stackoverflow
Solution 11 - JavaBoyangView Answer on Stackoverflow
Solution 12 - JavaEugeneView Answer on Stackoverflow