这两个语句是等效的吗?
Thread.sleep(0);
Thread.yield();
这两个语句是等效的吗?
Thread.sleep(0);
Thread.yield();
不是。最明显的区别在于sleep()
会抛出(已检查的)InterruptedException
异常。实际上,效果可能几乎相同,但这完全取决于实现。
我敢打赌,连续执行一百万次,sleep()
所需的时间会更长,因为系统计时器粒度可能经常导致它实际上要睡眠一段不可忽略的时间。
Thread.sleep(0)
和Thread.yield()
的效果如何“可能”相同? Thread.sleep(0)
难道不意味着根本没有休眠吗?如果答案是肯定的,那么它怎么能等同于Thread.yield()
,后者只是向操作系统调度程序发送信号以安排其他线程? - Geeksleep(0)
实际上意味着“根本不睡眠”,需要额外的逻辑将其变成无操作,而不是像处理其他数字一样将 0 视为“进入睡眠并立即唤醒”- 这也允许操作系统调度其他线程。由于在处理这种边缘情况时没有明显的好处,我预计大多数实现者不会这么做。 - Michael Borgwardtsleep(0)
可能会睡眠数十毫秒。 - Solomon SlowYield会将当前线程添加到就绪队列中,以便其他线程可以运行。Sleep不能保证放弃CPU。
这实际上取决于平台和JVM的版本。例如,在JDK 5(Hotspot)中的Windows下,yield()被字面上实现为Sleep(0) - 尽管我回忆起一个0的睡眠在Windows上会稍微特殊处理。但是在JDK 6中,yield()被实现为SwitchToThread()。
我之前整理了一些关于Thread.yield()的信息,包括一些可能感兴趣的实现细节。(您还可以查看我在同一网站上整理的有关Thread.sleep()的内容。)
OpenJDK源代码(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.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行代码。
[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();
}
Thread.Yield可以将CPU资源让给优先级更低的线程,而Thread.Sleep(0)只会将CPU让给优先级相等或更高的线程。
至少在Windows平台上是这样的 :)
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.
Thread.sleep() 和 Thread.yield() 做的事情是一样的,只不过在多处理器环境中,Thread.yield() 只会让运行在同一处理器上的线程放弃执行。