Sleep (0)和 Thread.product()语句是否等价?

这两个语句是等价的吗?

Thread.sleep(0);
Thread.yield();
39155 次浏览

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

屈服值()告诉 JVM 线程调度程序 可以给其他线 通常 JVM 使用这个 调用以激活 同样的线程优先级 抢占式多线程环境, 屈服()是不可操作的 在合作社中很重要 多线程环境,因为 没有产量,一根线就可以吃光 所有的中央处理器。

Sleep (x)告诉 JVM 线程 计划程序主动放置此线程 睡觉,不运行它,直到 至少 x 毫秒过去了。

既不睡觉() ,也不产生()变化 任何关于 同步锁。如果您的线程 有一个锁,你调用睡眠(1000) , 那么至少一秒钟就会过去 在你的思绪苏醒之前,当它 唤醒它可能决定释放 锁,或者它可能会抓住它 更久。

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

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

我敢打赌,连续执行每个操作100万次将使 很多的睡眠时间延长() ,因为系统计时器粒度可能经常导致它实际上睡眠了不可忽视的时间。

线头。屈服可以放弃 CPU 资源的线程与较低的优先级,而线程。Sleep (0)仅向具有相同或更高优先级的线程提供 CPU。

至少在 Windows 平台上是这样的:)

这实际上取决于 JVM 的平台和版本。例如,在 JDK 5(Hotspot)中的 Windows 下,虽然0的睡眠时间在我记得的 Windows 中略微有些特殊,但是屈服()实现为睡眠(0)。但是在 JDK 6中,屈服()是作为 Switch ToThread ()实现的。

不久前,我在 线程。屈服()上收集了一些信息,包括一些可能感兴趣的实现细节。(你可能还想看看我在同一个网站上放在 Thread.sleep ()上的东西。)

Thread.Sleep()的开销稍大一些,因为它创建了一个包含某种定时器的系统,该定时器将唤醒进程。(基本上取决于实施情况)
最后,它将调用 Yield()

Thread.Yield()会放弃这个回合,然后在下一回合获得它。

Thread.Sleep(0)可能有一个优化,只调用屈服。(同样,实现)

屈服()应该做的是创建当前正在运行的线程 返回可运行,以允许具有相同优先级的其他线程 所以目的是用屈服()来促进优雅 在同等优先级的线程之间轮流执行 方法不能保证做它声称的事情,即使 的确会导致线程退出运行并返回 可运行的,不能保证屈服的线程不仅仅是 因此,尽管屈服于强大的力量ーー而且常常是屈服于强大的力量 让一个正在运行的线程放弃它的插槽给另一个正在运行的线程 同样的优先权,不能保证。

屈服值()永远不会导致线程进入等待/睡眠/状态 阻塞状态。最多,一个屈服()将导致一个线程从 运行到可运行,但是,它可能根本没有任何效果。

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

OpenJDK source (Java SE 7)在 jvm.cpp 的 JVM_Sleep函数中为 Thread.sleep(0)实现了以下实现:

  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.production ()的实现具有以下代码:

  // 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简单得多。 例如: Linux 的 os::yield只调用 sched_yield(),而 os::sleep有大约70行代码。

Sleep () 线程。屈服()做同样的事情,只不过在多处理器环境中,线程。屈服()只放弃运行在同一处理器上的线程。

著名的 Brian Goetz 的著作《 Java 并发实践》(2006年出版,但仍然基本有效)就这个问题提出了以下观点。

产量和睡眠(0)的语义是未定义的[ JLS17.9] ; JVM 可以自由地将它们实现为 no-ops 或将它们视为调度提示。尤其是,它们不需要在 Unix 系统上具有 sleep (0)的语义ーー将当前线程放在运行队列的末尾,以获得该优先级,从而让位于具有相同优先级的其他线程ーー尽管一些 JVM 以这种方式实现屈服。

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

它依赖于平台和实现,而且它们可能并不等价。

下面的代码片段在使用 Thread.sleep (0)时,大多数情况下会给出输出:

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

而在使用 Thread.屈服()时,大多数情况下会给出:

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