如果我有一个等待锁的线程被阻塞,操作系统是否可以重新调度该线程来执行其他工作,直到锁可用?据我所知,它不能被重新调度,它只是处于空闲状态,直到它能够获得锁。但它看起来就是效率低下。如果我们有100个任务提交给一个ExecutorService,池中有10个线程:如果其中一个线程持有锁,而其他9个线程正在等待那个锁,那么只有持有锁的线程才能取得进展。我曾设想阻塞的线程可能会被临时重新调度,以运行其他一些提交的任务。
发布于 2021-04-10 01:42:15
你说过:
我曾想过阻塞的线程可能会被临时重新调度,以运行一些其他提交的任务。
项目织机
您所描述的虚拟线程(纤程)是作为未来版本的一部分而开发的。
目前,Java的OpenJDK实现使用来自主机操作系统的线程作为Java线程。因此,这些线程的调度实际上是由OS而不是JVM控制的。是的,正如您所描述的,在所有常见的OSes上,当Java代码阻塞时,代码的线程处于空闲状态。
项目织布机在“真实”平台/内核线程之上分层虚拟线程。可以将许多虚拟线程映射到每个真实线程。在普通硬件上运行数百万个线程是可能的。
使用Loom技术,JVM可以检测阻塞代码。被阻塞的代码的虚拟线程被“驻留”,并将另一个虚拟线程分配给实际线程,以便在驻留的线程等待响应时完成一些执行时间。这种停车和切换非常快,开销很小。在织布机技术下,阻塞变得非常“便宜”。
在大多数面向业务的普通应用程序中,阻塞是相当常见的。阻塞发生在文件I/O、网络I/O、数据库访问、日志记录、控制台交互、GUI等方面。这些使用虚拟线程的应用程序在Project Loom的实验构建中看到了巨大的性能提升。这些构建现已可用,基于早期访问的Java 17。项目织布机团队寻求反馈。
使用虚拟线程非常简单:切换您选择的executor服务。
ExecutorService executorService = Executors.newVirtualThreadExecutor() ;
注意:作为commented by Michael,由JVM管理的虚拟线程依赖于由主机操作系统管理的平台/内核线程。归根结底,即使在织机下,执行也是由操作系统调度的。当阻塞的Java线程在CPU核心上处于空闲状态时,虚拟线程非常有用。如果主机负载过重,Java线程可能会看到很少的执行时间,不管有没有虚拟线程。
虚拟线程不适合于很少阻塞的任务,也就是真正的CPU-bound任务。例如,编码视频。这样的任务应该继续使用传统的线程。
有关更多信息,请参阅对Oracle的Ron Pressler或织布机团队其他成员的启发性演示和采访。寻找最新的,因为织布机已经进化。
发布于 2021-04-10 02:06:29
我曾想过阻塞的线程可能会被临时重新调度,以运行一些其他提交的任务。
这就是其他线程的用途。如果您创建了X个线程,而Y线程被阻塞,则您有剩余的X-Y线程来执行其他提交的任务。据推测,选择数字X是为了获得实现和/或程序员认为最好的并发任务的数量。
您在问为什么实现不会忽略这个决定。答案是,合理地选择线程的数量比让实现忽略该选择更有意义。
发布于 2021-04-10 02:12:00
你部分地说对了。
在您描述的executor服务场景中,所有9个线程都将被阻塞,只有一个线程会取得进展。是真的。
你不太正确的部分是当你试图期望操作系统和Java的行为结合在一起的时候。看,线程的概念同时存在于操作系统和Java级别。但这是两件不同的事情。所以有Java线程和OS线程。Java线程是通过操作系统线程实现的。
想象一下,JVM中有(比方说) 10个Java-Thread,有些正在运行,有些没有。Java借用了一些OS-Thread来实现Java线程的运行。现在,当Java-Thread被阻塞(不管是什么原因)时,我们可以确定的是Java-Thread已经被阻塞了。我们很难观察到底层OS-Thread发生了什么。
操作系统可以回收OS-Thread并将其用于其他用途,也可以保持阻塞状态--这取决于具体情况。但是,即使OS-Thread被重用,Java-Thread仍然会被阻塞。在您的线程池场景中,九个Java-Thread仍然会被阻塞,并且只有一个Java- thread可以工作。
https://stackoverflow.com/questions/67025555
复制相似问题