Thread.sleep(0)和Thread.yield()语句是否相等?
这两个陈述是否相同?
Thread.sleep(0); Thread.yield();
不,最明显的区别是sleep()
抛出(checked) InterruptedException
。 在实践中,效果可能几乎相同,但完全依赖于实现。
我敢打赌,每一百万次连续做睡眠需要更长的时间(),因为系统计时器粒度可能经常导致其实际睡眠时间不可忽视。
Yield将当前线程添加到就绪队列,并允许其他线程运行。 睡眠不保证放弃CPU。
这实际上取决于JVM的平台和版本。 例如,在JDK 5(Hotspot)中的Windows下,yield()实际上被实现为Sleep(0) – 尽pipe我记得Windows的睡眠稍微被Windows处理。 但是在JDK 6中,yield()被实现为SwitchToThread()。
我刚才在Thread.yield()上汇集了一些信息,包括一些可能感兴趣的实现细节。 (你也可能想看到Thread.sleep()上的东西放在一起)。
yield()告诉JVM线程调度程序可以给予其他线程时间片。 通常JVM使用这个调用来激活具有相同线程优先级的另一个线程。 在一个良好的抢先式multithreading环境中,yield()是一个no-op。 然而,在一个合作的multithreading环境中,这是非常重要的,因为没有yield(),一个线程可能会吃掉所有的CPU。
sleep(x)指示JVM线程调度程序主动将此线程置于睡眠状态,并在至lessx毫秒之后再次运行。
sleep()和yield()都不会改变同步锁的状态。 如果你的线程有一个锁,并且你调用sleep(1000),那么在你的线程唤醒之前,至less有一秒钟会过去。 当它醒来时,它可能会决定释放锁,或者可能会持续更长的时间。
消息来源: http ://www.jguru.com/faq/view.jsp?EID= 425624
对于JVM_Sleep
函数中的Thread.sleep(0)
,OpenJDK源代码(Java SE 7)具有以下实现:
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); } }
Thread.yield()的实现有以下代码:
// 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(); }
所以Thread.sleep(0)
和Thread.yield()
可能会在某些平台上调用相同的系统调用。
os::sleep
和os::yield
是平台特定的东西。 在Linux和Windows上: os::yield
似乎比os::sleep
简单得多。 例如:Linux的os::yield
只调用sched_yield()
。 而且os::sleep
有大约70行代码。
着名的Brian Goetz的书“Java Concurrency in Practice”(2006年出版,但仍然基本有效)在这个问题上说了以下内容。
Thread.yield和Thread.sleep(0)的语义是未定义的[JLS17.9]; JVM可以自由地将它们实现为无操作或将它们视为调度提示。 特别是,它们不需要在Unix系统上具有睡眠(0)的语义 – 将当前线程放在运行队列的末尾,以产生相同优先级的其他线程 – 尽pipe一些JVM在这条路。
剩下的人可以在Javadoc页面find。
Thread.Yield可以放弃CPU资源给较低优先级的线程,而Thread.Sleep(0)只放弃CPU优先级相同或更高的线程。
至less在Windows平台上:)
除了Thread.yield()仅放弃在多处理器环境中的同一处理器上运行的线程之外, Thread.sleep()和Thread.yield()可以做同样的事情。
Thread.Sleep()
有一个稍大的开销,因为它创build了一个包含某种定时器的系统来唤醒进程。 (基本上取决于实施)
底线将最后调用Yield()
。
Thread.Yield()
将放弃该线程,并在下一轮获得它。
Thread.Sleep(0)
可能有一个优化来调用yield。 (再次实施)
yield()应该做的是使当前正在运行的线程返回到可运行状态,以允许具有相同优先级的其他线程轮到它们。 所以我们的目的是使用yield()来促进优先级相同的线程之间的优雅转换。 但实际上,yield()方法并不能保证它所做的事情是一致的,即使yield()确实导致线程退出运行并返回到runnable,也不能保证yielding线程不会再次select所有其他人! 所以,虽然yield()可能(而且经常)会使一个正在运行的线程放弃它的槽到另一个相同优先级的可运行线程,但是没有保证。
yield()永远不会导致线程进入等待/睡眠/阻塞状态。 yield()最多会导致一个线程从正在运行的状态转移到可运行状态,但是再一次,它可能根本就没有任何作用。
资料来源:SCJP Sunauthentication程序员书
它依赖于平台和实现,而且可能不等同。
下面的代码片段,当使用Thread.sleep(0)时,大部分时间都会输出:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
而使用Thread.yield()时,主要给出:
[0, 1, 1, 1, 1, 1, 1, 1, 1, 1] [0, 2, 2, 2, 2, 2, 2, 2, 2, 2]
请参阅下面的代码片段:
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(); }
不,它们不是等价的,除了上面的解释之外,我认为有必要检查yield
的Javadoc。 除非下面的情况符合,否则使用yield
似乎不是一个好主意。
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.