Thread 的 onSpinWait () 方法 class - Java 9
onSpinWait() method of Thread class - Java 9
在学习 Java 9 个特征时,我遇到了 Thread
class 的新方法,称为 onSpinWait
。根据 javadocs,此方法用于此:
Indicates that the caller is momentarily unable to progress, until the
occurrence of one or more actions on the part of other activities.
有人可以通过现实生活中的例子或场景帮助我理解这种方法吗?
纯系统提示!
阅读this article我引用:
Goals
Define an API that would allow Java code to hint to the run-time system that it is in a spin loop. The API will be a pure hint, and will carry no semantic behaviour requirements (for example, a no-op is a valid implementation). Allow the JVM to benefit from spin loop specific behaviours that may be useful on certain hardware platforms. Provide both a no-op implementation and an intrinsic implementation in the JDK, and demonstrate an execution benefit on at least one major hardware platform.
很多时候一个线程必须被挂起,直到它的范围之外的东西发生变化。一个(曾经)常见的做法是 wait() notify()
模式,其中一个线程等待另一个线程唤醒它们。
这有一个很大的限制,即其他线程必须意识到可能有等待线程并且应该通知。如果另一个线程的工作不在您的控制范围内,则无法收到通知。
唯一的方法是自旋等待。假设您有一个检查新电子邮件并通知用户的程序:
while(true) {
while(!newEmailArrived()) {
}
makeNotification();
}
这段代码每秒将执行数百万次;一遍又一遍地旋转,使用宝贵的电力和 CPU 动力。这样做的一种常见方法是在每次迭代时等待几秒钟。
while(true) {
while(!newEmailArrived()) {
try {
Thread.sleep(5000);
} catch(InterruptedException e) {
}
}
makeNotification();
}
这做得很好。但在您必须立即工作的情况下,睡眠可能是不可能的。
Java 9 试图通过引入这个新方法来解决这个问题:
while(true) {
while(!newEmailArrived()) {
Thread.onSpinWait();
}
makeNotification();
}
这将与没有方法调用的情况完全相同,但系统可以自由降低进程优先级;当其他更重要的事情需要其资源时,减慢循环或减少此循环的电力。
它与 x86 操作码 PAUSE
相同(并且可能编译为)并且等效于 Win32 宏 YieldProcessor
、GCC 的 __mm_pause()
和 C# 方法 Thread.SpinWait
这是一种非常弱化的屈服形式:它告诉你的 CPU 你正处于一个循环中,这个循环可能会消耗许多 CPU 循环等待某事发生(忙等待)。
这样,CPU 可以将更多资源分配给其他线程,而无需实际加载 OS 调度程序并使准备就绪的 运行 线程出队(这可能很昂贵).
自旋锁的一个常见用途是,当您知道共享内存上的争用很少见或很快完成时,自旋锁可能比普通锁表现更好。
此类的伪代码如下所示:
int state = 0; //1 - locked, 0 - unlocked
routine lock:
while state.cas(new_value=1, wanted_value=0) == false //if state is 0 (unlocked), store 1 (locked) and return true, otherwise just return false.
yield
routine unlock:
atomic_store(state,0)
yield
可以用Thread.onSpinWait()
来实现,暗示在尝试加锁的同时,CPU可以给其他线程更多的资源。
这种让步技术在实现无锁算法时非常普遍和流行,因为它们中的大多数都依赖于忙等待(几乎总是作为原子比较和交换循环实现)。这具有您可以想象的所有实际用途。
我只是想在阅读文档及其源代码后加我的 2 美分。此方法 可能 触发一些优化,也可能不会 - 所以必须小心 - 你不能真正依赖它 - 因为这是 hint
到 CPU
不仅仅是需求,可能没有任何初始依赖......这意味着它的实际源代码如下所示:
@HotSpotIntrinsicCandidate
public static void onSpinWait() {}
根据 this
,这实际上意味着此方法基本上是 NO-OP,直到它到达 JIT
中的 c2 compiler
举一个现实世界的例子,
假设您想实现异步日志记录,其中想要记录某些内容的线程不想等待他们的日志消息获得 "published" (比如写入文件),只要它最终完成(因为他们有真正的工作要做。)
Producer(s):
concurrentQueue.push("Log my message")
然后说,您决定拥有一个专用的消费者线程,它完全负责实际将日志消息写入文件:
(Single)Consumer
while (concurrentQueue.isEmpty())
{
//what should I do?
}
writeToFile(concurrentQueue.popHead());
//loop
问题是在 while 块中做什么? Java 没有提供理想的解决方案:你可以做一个 Thread.sleep(),但是要多长时间,那是重量级的;或 Thread.yield(),但这是未指定的,或者您可以使用锁或互斥*,但这通常过于重量级并且也会减慢生产者的速度(并且破坏了异步日志记录的既定目的)。
你真正想要的是对运行时说,"I anticipate that I won't be waiting too long, but I'd like to minimize any overhead in waiting/negative effects on other threads"。
这就是 Thread.onSpinWait() 的用武之地。
正如上面的响应所示,在支持它的平台(如 x86)上,onSpinWait() 被内化为 PAUSE 指令,这将为您提供所需的好处。所以:
(Single)Consumer
while (concurrentQueue.isEmpty())
{
Thread.onSpinWait();
}
writeToFile(concurrentQueue.popHead());
//loop
shown empirically 这可以改善 "busy-waiting" 样式循环的延迟。
我还想澄清一下,它不仅对实施 "spin-locks" 有用(尽管在这种情况下肯定有用);上面的代码不需要任何类型的锁(自旋或其他)。
要想入得了杂草,莫过于Intel's specs
*为清楚起见,JVM 在尝试最小化互斥锁的成本方面非常聪明,并且最初将使用轻量级锁,但那是另一个讨论。
在学习 Java 9 个特征时,我遇到了 Thread
class 的新方法,称为 onSpinWait
。根据 javadocs,此方法用于此:
Indicates that the caller is momentarily unable to progress, until the occurrence of one or more actions on the part of other activities.
有人可以通过现实生活中的例子或场景帮助我理解这种方法吗?
纯系统提示!
阅读this article我引用:
Goals
Define an API that would allow Java code to hint to the run-time system that it is in a spin loop. The API will be a pure hint, and will carry no semantic behaviour requirements (for example, a no-op is a valid implementation). Allow the JVM to benefit from spin loop specific behaviours that may be useful on certain hardware platforms. Provide both a no-op implementation and an intrinsic implementation in the JDK, and demonstrate an execution benefit on at least one major hardware platform.
很多时候一个线程必须被挂起,直到它的范围之外的东西发生变化。一个(曾经)常见的做法是 wait() notify()
模式,其中一个线程等待另一个线程唤醒它们。
这有一个很大的限制,即其他线程必须意识到可能有等待线程并且应该通知。如果另一个线程的工作不在您的控制范围内,则无法收到通知。
唯一的方法是自旋等待。假设您有一个检查新电子邮件并通知用户的程序:
while(true) {
while(!newEmailArrived()) {
}
makeNotification();
}
这段代码每秒将执行数百万次;一遍又一遍地旋转,使用宝贵的电力和 CPU 动力。这样做的一种常见方法是在每次迭代时等待几秒钟。
while(true) {
while(!newEmailArrived()) {
try {
Thread.sleep(5000);
} catch(InterruptedException e) {
}
}
makeNotification();
}
这做得很好。但在您必须立即工作的情况下,睡眠可能是不可能的。
Java 9 试图通过引入这个新方法来解决这个问题:
while(true) {
while(!newEmailArrived()) {
Thread.onSpinWait();
}
makeNotification();
}
这将与没有方法调用的情况完全相同,但系统可以自由降低进程优先级;当其他更重要的事情需要其资源时,减慢循环或减少此循环的电力。
它与 x86 操作码 PAUSE
相同(并且可能编译为)并且等效于 Win32 宏 YieldProcessor
、GCC 的 __mm_pause()
和 C# 方法 Thread.SpinWait
这是一种非常弱化的屈服形式:它告诉你的 CPU 你正处于一个循环中,这个循环可能会消耗许多 CPU 循环等待某事发生(忙等待)。
这样,CPU 可以将更多资源分配给其他线程,而无需实际加载 OS 调度程序并使准备就绪的 运行 线程出队(这可能很昂贵).
自旋锁的一个常见用途是,当您知道共享内存上的争用很少见或很快完成时,自旋锁可能比普通锁表现更好。
此类的伪代码如下所示:
int state = 0; //1 - locked, 0 - unlocked
routine lock:
while state.cas(new_value=1, wanted_value=0) == false //if state is 0 (unlocked), store 1 (locked) and return true, otherwise just return false.
yield
routine unlock:
atomic_store(state,0)
yield
可以用Thread.onSpinWait()
来实现,暗示在尝试加锁的同时,CPU可以给其他线程更多的资源。
这种让步技术在实现无锁算法时非常普遍和流行,因为它们中的大多数都依赖于忙等待(几乎总是作为原子比较和交换循环实现)。这具有您可以想象的所有实际用途。
我只是想在阅读文档及其源代码后加我的 2 美分。此方法 可能 触发一些优化,也可能不会 - 所以必须小心 - 你不能真正依赖它 - 因为这是 hint
到 CPU
不仅仅是需求,可能没有任何初始依赖......这意味着它的实际源代码如下所示:
@HotSpotIntrinsicCandidate
public static void onSpinWait() {}
根据 this
,这实际上意味着此方法基本上是 NO-OP,直到它到达JIT
中的 c2 compiler
举一个现实世界的例子, 假设您想实现异步日志记录,其中想要记录某些内容的线程不想等待他们的日志消息获得 "published" (比如写入文件),只要它最终完成(因为他们有真正的工作要做。)
Producer(s):
concurrentQueue.push("Log my message")
然后说,您决定拥有一个专用的消费者线程,它完全负责实际将日志消息写入文件:
(Single)Consumer
while (concurrentQueue.isEmpty())
{
//what should I do?
}
writeToFile(concurrentQueue.popHead());
//loop
问题是在 while 块中做什么? Java 没有提供理想的解决方案:你可以做一个 Thread.sleep(),但是要多长时间,那是重量级的;或 Thread.yield(),但这是未指定的,或者您可以使用锁或互斥*,但这通常过于重量级并且也会减慢生产者的速度(并且破坏了异步日志记录的既定目的)。
你真正想要的是对运行时说,"I anticipate that I won't be waiting too long, but I'd like to minimize any overhead in waiting/negative effects on other threads"。 这就是 Thread.onSpinWait() 的用武之地。
正如上面的响应所示,在支持它的平台(如 x86)上,onSpinWait() 被内化为 PAUSE 指令,这将为您提供所需的好处。所以:
(Single)Consumer
while (concurrentQueue.isEmpty())
{
Thread.onSpinWait();
}
writeToFile(concurrentQueue.popHead());
//loop
shown empirically 这可以改善 "busy-waiting" 样式循环的延迟。
我还想澄清一下,它不仅对实施 "spin-locks" 有用(尽管在这种情况下肯定有用);上面的代码不需要任何类型的锁(自旋或其他)。
要想入得了杂草,莫过于Intel's specs
*为清楚起见,JVM 在尝试最小化互斥锁的成本方面非常聪明,并且最初将使用轻量级锁,但那是另一个讨论。