据我所知,最常见的 JVM 并发 API 之一:futures - 至少在 scala 中实现 - 依赖用户代码在线程可能处于空闲状态时放弃它。在 scala 中,它通常被称为“避免阻塞”,开发人员必须在任何有意义的地方实现它。效率不高。
JVM 是否有一些完全固有的东西,可以防止 JVM 将线程的上下文切换到新任务 - 当线程空闲时 - 由操作系统进程调度程序实现?
据我所知,最常见的 JVM 并发 API 之一:futures - 至少在 scala 中实现 - 依赖用户代码在线程可能处于空闲状态时放弃它。在 scala 中,它通常被称为“避免阻塞”,开发人员必须在任何有意义的地方实现它。效率不高。
JVM 是否有一些完全固有的东西,可以防止 JVM 将线程的上下文切换到新任务 - 当线程空闲时 - 由操作系统进程调度程序实现?
JVM 是否有一些完全固有的东西,可以防止 JVM 将线程的上下文切换到新任务 - 当线程空闲时 - 由操作系统进程调度程序实现?
大多数情况下,这种切换必须合作完成。每个单独的阻塞方法都必须以允许任务在完成后恢复的方式进行包装或重新实现,毕竟,不再有本地线程等待阻塞操作的完成。
虽然这原则上可以针对 JVM 内部阻塞方法完成,但考虑通过 JNI 执行的任意本机代码,JVM 不知道如何堆栈切换这些本机线程,它们毕竟被困在本机代码中。
您可能想看看quasar,据我了解,他们为一些 JDK 内部方法实现了这样的包装器或等价物,例如sleep
, park
/ unpark
,基于通道的 IO 和其他一些允许它们的纤维(以及期货在这些纤程上运行)以在它们等待完成时执行这种用户模式上下文切换。
编辑:单独的 JNI 已经足以将用户模式任务切换限制为机会主义优化,当本机代码阻塞线程时,可能不得不退回到启动额外的本机线程。
但这不是唯一的问题,例如,在 linux 上,真正的异步文件 IO 操作需要文件系统和内核支持(请参阅关于 AIO 的这个 SO 问题),并非所有人都提供。如果没有提供它,则必须使用额外的阻塞 IO 线程来模拟它,从而重新引入我们一开始就想避免的所有开销。最好只是阻塞线程池本身并启动额外的线程,至少我们会避免这种方式的线程间通信。
内存映射文件也可以阻塞线程并强制操作系统调度程序由于页面错误而暂停线程,我不知道与虚拟内存系统合作来避免这种情况的方法。
更不用说虚拟机上的所有阻塞调用都必须使用操作系统提供的异步等效项重新实现。错过一个,你就会有一个阻塞的线程。如果您有一个阻塞的线程,您的线程池将需要一个自动增长功能,我们又回到了原点。
最后但并非最不重要的一点是,在某些情况下,可能需要阻塞、每个文件描述符一个线程 IO。保证用户模式切换所需的普遍更改可能会破坏这些更改。
所以总而言之,有时用户模式切换是可能的。但是 JVM 不能对此做出硬性保证,因此无论如何它都必须实现所有本机线程处理,并且程序员将至少在某种程度上与执行这些期货的线程池的假设合作编写代码。有些情况可以消除,但不是全部。