Thread.sleep(0)和Thread.yield()语句是否相同?

时间:2009-10-21 12:45:04

标签: java multithreading

这两个陈述是否相同?

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

12 个答案:

答案 0 :(得分:41)

没有。最明显的区别是sleep()抛出(已检查)InterruptedException。在实践中,效果可能几乎相同,但它完全依赖于实现。

我敢打赌连续每次做一百万次会使更长时间用于睡眠(),因为系统计时器粒度可能经常导致它实际上睡眠的时间不可忽略不计时间。

答案 1 :(得分:32)

Yield将当前线程添加到就绪队列并允许其他线程运行。睡眠不能保证放弃cpu。

答案 2 :(得分:29)

这实际上取决于JVM的平台和版本。例如,在JDK 5(Hotspot)中的Windows下,yield()实际上是作为Sleep(0)实现的 - 尽管我记得睡眠为0时稍微特别被Windows处理。但在JDK 6中,yield()实现为SwitchToThread()。

我不久前在Thread.yield()上汇总了一些信息,包括一些可能感兴趣的实施细节。 (您可能还希望在Thread.sleep()上看到我放在同一网站上的内容。)

答案 3 :(得分:13)

OpenJDK源代码(Java SE 7)对jvm.cpp的Thread.sleep(0)函数中的JVM_Sleep具有以下实现:

  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::sleepos::yield是特定于平台的内容。 在Linux和Windows上:os::yield似乎比os::sleep简单得多。 例如:os::yield Linux仅调用sched_yield()os::sleep有大约70行代码。

答案 4 :(得分:10)

  

yield()告诉JVM线程调度程序   给其他线程是可以的   时间片。通常JVM使用它   调用激活另一个线程   相同的线程优先级好的   抢占式多线程环境,   yield()是一个无操作。但是,确实如此   在合作社中很重要   多线程环境,因为   没有yield(),一个线程可以吃掉   所有的CPU。

     

sleep(x)告诉JVM线程   调度程序主动放置此线程   睡觉,而不是再次运行,直到   至少已经过了x毫秒。

     

sleep()和yield()都没有变化   关于状态的任何事情   同步锁。如果你的线程   有锁,你叫睡觉(1000),   然后至少会经过一秒钟   在你的线程醒来之前。当它   醒来它可能决定释放   锁定 - 或者它可以保持它   更长的时间。

消息来源:http://www.jguru.com/faq/view.jsp?EID=425624

答案 5 :(得分:7)

着名的Brian Goetz的书“Java Concurrency in Practice”(2006年出版,但仍然基本上有效)在这个问题上说了以下内容。

  

Thread.yield和Thread.sleep(0)的语义未定义[JLS17.9]; JVM可以自由地将它们实现为no-ops或将它们视为调度提示。特别是,它们不需要在Unix系统上具有sleep(0)的语义 - 将当前线程放在该优先级的运行队列的末尾,产生相同优先级的其他线程 - 尽管一些JVM实现了产量这条路。

其余人可以在Javadoc页面中找到。

答案 6 :(得分:1)

Thread.Yield可以放弃具有较低优先级的线程的CPU资源,而Thread.Sleep(0)仅将CPU放弃给具有相同或更高优先级的线程。

至少在Windows平台上:)

答案 7 :(得分:1)

Thread.sleep() Thread.yield()做同样的事情,除了 Thread.yield()只放弃线程在多处理器环境中运行在同一个处理器上。

答案 8 :(得分:0)

Thread.Sleep()的开销略大,因为它会创建一个包含某种计时器的系统,该计时器将唤醒进程。 (主要取决于实施)
最后,它最终会调用Yield()

Thread.Yield()只是放弃线程,并在下一轮获得它。

Thread.Sleep(0)可能会优化调用yield。 (再次,实施)

答案 9 :(得分:0)

  

yield()应该做的是使当前运行的线程   返回runnable以允许具有相同优先级的其他线程   轮到他们了。所以意图是使用yield()来促进优雅   在优先级相同的线程中轮换。但实际上,   yield()方法不保证做它声称的,即使   yield()会导致线程退出运行并返回   runnable,不能保证屈服线程不会   再次选择所有其他人!因此,虽然yield()可能 - 而且经常   确保一个正在运行的线程将其槽放弃到另一个可运行的线程   同样优先,没有保证。

     

yield()不会导致线程进入等待/休眠/   阻止状态。 yield()最多会导致一个线程出现   运行到可运行,但同样,它可能根本没有效果。

资料来源:SCJP Sun认证程序员书

答案 10 :(得分:0)

它依赖于平台和实现,它们可能不相同。

下面的代码片段,当使用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();
}

答案 11 :(得分:0)

不,它们不相同,除了上面的解释, 我认为有必要检查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.