JVM 线程管理 v.s。 OS 调度

JVM thread management v.s. OS scheduling

据我所知,最常见的 JVM 并发之一 API:futures - 至少在 scala 中实现 - 依赖于用户代码在线程可能等待空闲时放弃线程。在 scala 中,它通常被称为 "avoiding blocking",开发人员必须在任何有意义的地方实现它。 效率不高。

是否有 JVM 完全固有的东西阻止 JVM 将线程的上下文切换到新任务 - 当线程空闲时 - 由操作系统进程调度程序实现?

Is there something very entirely inherent to the JVM, that prevents the JVM switching the context of a thread to new tasks - when the thread is idle - as implemented by operating system process schedulers?

主要是这种切换需要配合完成。每个单独的阻塞方法都必须以允许任务在完成后恢复的方式包装或重新实现,毕竟,不再有等待阻塞操作完成的本机线程。

虽然原则上这可以针对 JVM 内部阻塞方法完成,但考虑通过 JNI 执行的任意本机代码,JVM 不知道如何堆栈切换这些本机线程,它们在之后被卡在本机代码中全部.

您可能想看看 quasar,据我了解,他们为某些 JDK 内部方法(例如 sleeppark/unpark、基于通道的 IO 和其他一些允许它们的纤程(以及这些纤程上的期货 运行)在它们执行时恰好执行那种用户模式上下文切换等待完成。

编辑:单独 JNI 已经足以 将用户模式任务切换限制为一种机会主义优化,当本机代码阻塞时可能不得不回退以启动额外的本机线程一个线程。

但这不是唯一的问题,例如 linux 真正的异步文件 IO 操作需要文件系统和内核支持(请参阅此 SO question on AIO),并非所有这些都提供。在没有提供的地方,必须使用额外的阻塞 IO 线程来模拟它,从而重新引入我们一开始想要避免的所有开销。也可以只阻塞线程池本身并启动额外的线程,至少我们会以这种方式避免线程间通信。

内存映射文件也可以阻塞线程并强制 OS-scheduler 由于页面错误而挂起线程,我不知道与虚拟内存系统合作以避免这种情况的方法.

更不用说 VM 上的 所有 阻塞调用都必须使用 OS 提供的异步等效项重新实现。甚至错过一个,你就会有一个阻塞的线程。如果您有一个阻塞的线程,您的线程池将需要一个自动增长功能,我们回到原点。

最后但同样重要的是,在某些情况下,可能需要阻塞、每个文件描述符一个线程的 IO。保证用户模式切换所需的普遍更改可能会破坏这些更改。

所以总而言之,用户模式切换是可能的,有时。但是 JVM 无法对此做出硬性保证,因此无论如何它都必须实现所有本机线程处理,并且程序员将至少在某种程度上与线程池执行这些未来的假设进行协作。有些情况可以消除,但不是全部。