标题基本上说明了所有内容,还有我真的很想知道何时使用它们的少量补充。可能很简单-我已经阅读了它们的文档,但仍然不能说出太多区别。
这里有this之类的答案,基本上都是这样:
屈服对于忙碌的等待也很有用...
我不太同意他们的原因,原因很简单:ForkJoinPool
在内部使用Thread::yield
,这是jdk世界中的一个很新的功能。
真正困扰我的是jdk中的用法(StampledLock::tryDecReaderOverflow
):
else if ((LockSupport.nextSecondarySeed() & OVERFLOW_YIELD_RATE) == 0)
Thread.yield();
else
Thread.onSpinWait();
return 0L;
因此,似乎在某些情况下,一个优先于另一个。而且,不,我没有实际的例子可能需要我使用它-我实际使用的唯一例子是Thread::onSpinWait
,因为1)我碰巧忙于等待2)这个名字很能说明我应该在忙碌的旋转中使用它。
答案 0 :(得分:6)
当阻塞线程时,有几种策略可供选择:旋转,wait()
/ notify()
或两者结合。对变量进行纯旋转是一种非常低的延迟策略,但是它可能会使其他竞争CPU时间的线程饿死。另一方面,wait()
/ notify()
可以为其他线程释放CPU,但是在对线程进行调度时可能会花费数千个CPU周期的延迟。
那么如何避免纯旋转以及与调度和调度阻塞线程相关的开销?
Thread.yield()
是对线程调度程序的提示,如果准备好另一个具有相同或更高优先级的线程,则放弃它的时间片。这样可以避免纯粹的自旋,但不能避免重新安排线程的开销。
最新添加的是Thread.onSpinWait()
,它插入特定于体系结构的指令,以提示处理器线程处于自旋循环中。在x86上,这可能是PAUSE
指令,在aarch64上,这是YIELD
指令。
这些说明有什么用?在纯自旋循环中,处理器将一次又一次地推测性地执行循环,以填满管道。当线程旋转的变量最终改变时,由于违反内存顺序,所有的推测性工作将被丢弃。真浪费!
给处理器的提示可能会阻止流水线推测性地执行自旋循环,直到提交了先前的存储器指令为止。在SMT(超线程)的情况下,这很有用,因为可以为其他硬件线程释放管道。