thread class 的 onSpinWait() 方法 - Java 9

在学习Java 9功能时,我遇到了一种新的类方法,称为onSpinWait。根据javadocs,此方法用于此:Thread

指示调用方暂时无法前进,直到其他活动发生一个或多个操作。

有人能帮助我理解这种方法,给出一个现实生活中的例子或场景吗?


答案 1

它与x86操作码相同(并且可能编译为),相当于Win32宏,GCC和C#方法PAUSEYieldProcessor__mm_pause()Thread.SpinWait

这是一种非常弱化的屈服形式:它告诉你的CPU你处于一个循环中,可能会消耗许多CPU周期等待某些事情发生(忙碌等待)。

这样,CPU可以将更多资源分配给其他线程,而无需实际加载操作系统调度程序并使准备运行的线程排出队列(这可能很昂贵)。

它的常见用法是自旋锁定,当您知道共享内存上的争用非常不频繁或完成得非常快时,自旋锁可能比普通锁更好。

此类伪代码可能如下所示:

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可以使用 来实现,提示在尝试锁定锁的同时,CPU 可以向其他线程提供更多资源。Thread.onSpinWait()

在实现无锁算法时,这种良率技术非常普遍和流行,因为它们中的大多数都依赖于忙等待(几乎总是作为原子比较和交换循环实现)。这具有您可以想象的所有实际用途。


答案 2

纯系统提示!

阅读这篇文章,我引用:

目标

定义一个 API,该 API 将允许 Java 代码向运行时系统提示它位于旋转循环中。API 将是一个纯粹的提示,并且不带有语义行为要求(例如,no-op 是有效的实现)。允许 JVM 从特定于自旋循环的行为中受益,这些行为在某些硬件平台上可能很有用。在 JDK 中提供无操作实现和内部实现,并在至少一个主要硬件平台上展示执行优势。

很多时候,线程必须挂起,直到超出其范围的内容发生更改。一个(曾经)常见的做法是有一个线程等待另一个线程唤醒它们的模式。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();
}

这将与没有方法调用完全相同,但系统可以自由地降低进程优先级;当其他更重要的事情需要资源时,减慢循环或减少该环路的电力。


推荐