为什么 Java 线程既不轻量级如绿色线程又不支持多核? 由内部本地固定大小的本地线程池支持

问题描述

在 java 1.1 中,所有线程都在单个内核上运行(不利用机器的多个内核/cpu)并由 JVM 在用户空间(所谓的 green threads)中调度。

在 Java 1.2 / 1.3 左右(取决于底层操作系统),进行了更改并将 Java 线程对象映射到操作系统线程(Linux 情况下为 pthread),这充分利用了多核,但 OTOH 创建了一个线程在内存方面变得非常昂贵(因为操作系统线程的初始堆栈大小非常庞大),这严重限制了单台机器可以在线程每个请求模型中处理的并发请求数量。这需要服务器端架构切换到异步模型(引入了 non-blocking I/O 包,AsyncContext添加到 servlet API 等),这一直困扰着几代 Java 服务器端开发人员直到今天:起初,大多数 API 看起来像是针对每请求线程模型而设计的,需要仔细阅读 API 文档才能找到从侧面引导到它们的异步功能

直到最近,project Loom 才最终致力于提供由线程池(“旧式”Java 线程的 Java 线程池,它又映射到 OS 线程)支持的轻量级线程,从而结合了优势:创建大量使用多核的线程的成本很低,并且可以轻松地暂停阻塞操作(例如 I/O 等)。

为什么现在才发生这种情况,20 年后,而不是在 Java 1.3 中立即发生?即:为什么 Java 线程被制作成 1-1 映射到 OS 线程,而不是由 JVM 的内部线程池支持(执行),这些线程池的固定大小对应于可用的 cpu 内核?

在JVM中实现起来会不会很困难?
Java 服务器端开发人员在过去 20 年里被迫进行的所有异步编程以及 C/C++ 开发人员一直在做的事情似乎并不复杂,但也许我遗漏了一些东西。

另一种可能是 JVM 的架构设计中存在一些阻塞障碍,使其无法以这种方式实现。

更新:
Project Loom 的架构设计信息已根据评论更新:非常感谢!

解决方法

经过一番考虑,我认为将 Java 字节码 JIT 编译为本机代码可能是原因:
在我提出的模型中,Java 线程执行之间的原生 OS 线程切换将是从其工作队列中挑选一个元组 。但是由于JIT,java线程的栈基本上和backing OS线程的栈是一样的,不能像AFAIK那样替换。
因此,据我所知,只有当 JVM 每次都解释字节码并将 Java 线程的堆栈保留在其堆上时,我提议的实现方式才有可能,而事实并非如此。