为什么Java线程不能同时具有轻量级(如绿色线程)和多核功能?(由内部本机固定大小本机线程池支持)

为什么Java线程不能同时具有轻量级(如绿色线程)和多核功能?(由内部本机固定大小本机线程池支持),java,multithreading,jvm,java-threads,jvm-hotspot,Java,Multithreading,Jvm,Java Threads,Jvm Hotspot,在Java1.1中,所有线程都运行在单个内核上,没有利用机器的多核/CPU,由JVM在所谓的用户空间中调度 在Java 1.2/1.3前后,根据底层操作系统的不同,进行了更改,并将Java线程对象映射到Linux的操作系统线程pthreads,这充分利用了多核的优势,但OTOH创建线程在内存方面变得非常昂贵,因为操作系统线程的初始堆栈非常大,这在很大程度上限制了单台机器在每个请求线程模型中可以处理的并发请求的数量。引入了切换到异步模型包所需的服务器端架构,并将其添加到servlet API中,e

在Java1.1中,所有线程都运行在单个内核上,没有利用机器的多核/CPU,由JVM在所谓的用户空间中调度

在Java 1.2/1.3前后,根据底层操作系统的不同,进行了更改,并将Java线程对象映射到Linux的操作系统线程pthreads,这充分利用了多核的优势,但OTOH创建线程在内存方面变得非常昂贵,因为操作系统线程的初始堆栈非常大,这在很大程度上限制了单台机器在每个请求线程模型中可以处理的并发请求的数量。引入了切换到异步模型包所需的服务器端架构,并将其添加到servlet API中,etc一直困扰着几代Java服务器端开发人员:起初,大多数API看起来都是针对每个请求的线程模型设计的,我们需要仔细阅读API文档,从一个侧面找到为它们引导的异步功能

直到最近,我们才最终致力于提供由线程池支持的轻量级线程,一个由旧式Java线程组成的Java线程池,这反过来又映射到操作系统线程,从而结合了这些优点:创建大量使用多核的线程成本低廉,并且可以轻松地挂起阻塞操作(如I/O等)

为什么在Java 1.3中,20年后的现在才发生这种情况,而不是立即发生?ie:为什么Java线程被要求将1-1映射到OS线程,而不是由JVM的内部线程池支持执行,该线程池由与可用CPU内核相对应的固定大小的OS线程组成

在JVM中实现可能很困难吗? java服务器端开发人员在过去20年中被迫进行的所有异步编程,以及C/C++开发人员一直在做的事情,似乎没有比这复杂多少,但也许我遗漏了一些东西

另一种可能性是,JVM的体系结构设计中存在一些阻碍,阻止了它以这种方式实现

更新:
ProjectLoom的架构设计信息根据评论进行了更新:非常感谢

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

确切地说,为什么您现在要问这个问题?二十年后?我想您现在遇到了一个需要解决的技术问题?所以到底是什么?也许——只是猜测——这是因为技术已经进化了。或者,可能是因为底层硬件已经发展到了极点!在真正重要的地方。1存在绿色线程,这是一个糟糕的实现。2为什么您认为ProjectLowest需要这么多年才能实施?这是一项非常具有挑战性的任务。这不只是其中的一个,我们就这么做吧,到目前为止。在我看来,这将是运行时和语言有史以来最大的变化。3请记住HashSet——仍然在幕后使用HashMap,人们并不在意——事情仍然很好。对于loom来说,有很多挑战,比如线程局部变量,这应该是什么,如何工作?每个非承载线程有一个本地线程?如果是这样的话,当你屈服时,它将被存储在哪里,如何恢复?考虑到大量的轻量级线程,如何以及在哪里消耗这些内存?或者垃圾收集,您如何实现这些线程资源的良好收集?你以GC根的身份走他们的堆栈?都是吗?你可以看到,显而易见的一面并没有那么复杂,在幕后工作是巨大的。主题不是“异步编程(java服务器端开发人员在过去20年中被迫进行的编程)”和“轻量级线程”吗?因此,您的示例并不是关于轻量级线程的。你不断地在这些术语之间来回切换。二十年前,C/C++中的“异步编程”并不是什么新鲜事,有这样的API。本机pthread实现和所需的线程安全操作系统功能还处于起步阶段。相比之下,Java有线程支持,但当时没有“异步编程”API。因此,实际使用的方法是不同的。解释器通常也是本机软件的一部分,可以具有任意复杂的状态来保存和恢复,就像其他本机或JIT编译的代码一样。但是
当考虑到线程状态比您最初认为的更复杂时,您正朝着正确的方向前进。但另一点是,需要替换所有会阻止本机carrier线程锁定的操作,以及在引擎盖下使用非阻塞等效程序的操作系统调用,以执行轻量级任务切换,并在操作完成后切换回。@Holger yes,完全同意:所有的阻塞操作都需要在您编写时被替换,但这似乎并不是一个复杂的问题,只是解释程序代码中有很多繁琐的工作。无论如何,线程状态与我所想的完全一样,与您所建议的相反,只是因为对本机代码进行JIT编译,它存储在更低的操作系统级别,这使得很难/不可能按照我最初建议的方式进行切换。