Are Thread.sleep(0) and Thread.yield() statements equivalent?
JavaMultithreadingJava 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.
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.