75

Are these two statement equivalent?

Thread.sleep(0);
Thread.yield();
Joachim Sauer
  • 302,674
  • 57
  • 556
  • 614
Prady
  • 10,978
  • 39
  • 124
  • 176

12 Answers12

54

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.

Michael Borgwardt
  • 342,105
  • 78
  • 482
  • 720
  • that's a good point, something like sleep(1) may take much longer than 1 millisecond due to granularity. – z - Oct 21 '09 at 12:56
  • 2
    @Michael You wrote " In practice, the effect may be almost the same"..By reading the Javadocs I am not clear about the relevance of the question itself and fail to understand *in practice* how the effect *may be* the same for the two calls `Thread.sleep(0)` and `Thread.yield()`? Doesn't `Thread.sleep(0)` mean no sleep at all? If the answer is yes, then how can it be equated to `Thread.yield()` which is just sending a signal to the OS scheduler to schedule other threads? – Geek Sep 13 '13 at 14:08
  • 3
    @Geek: To get `sleep(0)` to actually mean "no sleep at all" would require extra logic to make it a no-op instead of treating the 0 like any other number, in which case it means "go to sleep and wake again immediately"- which *also* lets the OS schedule other threads. Since there's no obvious benefit from treating this edge case specially, I'd expect most implementors not to do it. – Michael Borgwardt Sep 13 '13 at 14:27
  • @MichaelBorgwardt I see the point of the question now.Thanks and +1 for your brilliant answer. – Geek Sep 13 '13 at 14:30
  • 2
    Treating 0 like any other number probably would _not_ mean, "...and wake up again immediately." It more likely would mean, "go to the top of the scheduler's heap, and wait there to become runnable _at the next scheduler heartbeat tick._ If zero is treated like any other number, then `sleep(0)` potentially could sleep for tens of milliseconds. – Solomon Slow Aug 16 '16 at 15:34
34

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

z -
  • 7,130
  • 3
  • 40
  • 68
34

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.)

Neil Coffey
  • 21,615
  • 7
  • 62
  • 83
17

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.

SKi
  • 8,007
  • 2
  • 26
  • 57
10

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

Roberto Aloi
  • 30,570
  • 21
  • 75
  • 112
  • 2
    Non-normative reference. Much of that is not in the Javadoc, and the part about 'JVM Thread Scheduler' has been imaginary for many years. – user207421 Apr 23 '15 at 05:18
9

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.

peter.petrov
  • 38,363
  • 16
  • 94
  • 159
2

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();
}
Boyang
  • 2,520
  • 5
  • 31
  • 49
1

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 :)

Vitaliy Liptchinsky
  • 5,221
  • 2
  • 18
  • 25
0

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

Grigor Nazaryan
  • 567
  • 5
  • 18
  • Somewhat incoherent non-normative reference. How can it be 'supposed' to do something if it isn't 'guaranteed' to do it? – user207421 Apr 23 '15 at 05:19
0

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.

0

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.
Eugene
  • 10,627
  • 5
  • 49
  • 67
0

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)

Yochai Timmer
  • 48,127
  • 24
  • 147
  • 185