Java 阻塞的线程是否可以重新调度以执行其他工作?

Java 阻塞的线程是否可以重新调度以执行其他工作?,java,multithreading,operating-system,Java,Multithreading,Operating System,如果有一个线程在等待锁定时被阻塞,操作系统是否可以重新安排该线程执行其他工作,直到锁定可用? 根据我的理解,它不能被重新调度,它只是在获得锁之前处于空闲状态。但这似乎效率低下。如果有100个任务提交给ExecutorService,并且池中有10个线程:如果其中一个线程持有锁,而其他9个线程正在等待该锁,那么只有持有锁的线程才能取得进展。我原以为被阻止的线程可以临时重新调度以运行其他一些提交的任务。您说过: 我本以为被阻止的线程可以临时重新调度以运行其他提交的任务 项目织机 您正好描述了作为Ja

如果有一个线程在等待锁定时被阻塞,操作系统是否可以重新安排该线程执行其他工作,直到锁定可用? 根据我的理解,它不能被重新调度,它只是在获得锁之前处于空闲状态。但这似乎效率低下。如果有100个任务提交给ExecutorService,并且池中有10个线程:如果其中一个线程持有锁,而其他9个线程正在等待该锁,那么只有持有锁的线程才能取得进展。我原以为被阻止的线程可以临时重新调度以运行其他一些提交的任务。

您说过:

我本以为被阻止的线程可以临时重新调度以运行其他提交的任务

项目织机 您正好描述了作为Java未来版本的一部分而开发的虚拟线程(光纤)

目前,Java的OpenJDK实现使用来自主机操作系统的线程作为Java线程。因此,这些线程的调度实际上是由操作系统而不是JVM控制的。是的,正如您所描述的,在所有常见的操作系统上,当Java代码阻塞时,代码的线程处于空闲状态

ProjectLowe在“真实”平台/内核线程之上分层虚拟线程。许多虚拟线程可能映射到每个真实线程。在通用硬件上运行数百万个线程是可能的

通过Loom技术,JVM可以检测阻塞代码。被阻塞代码的虚拟线程被“停驻”在一边,另一个虚拟线程被分配给该真实线程,以在停驻的线程等待响应时完成一些执行时间。这种停车和切换速度非常快,开销很小。在织机技术下,木块变得极其“便宜”

阻塞在大多数面向业务的普通应用程序中非常常见。阻塞发生在文件I/O、网络I/O、数据库访问、日志记录、控制台交互、GUI等方面。使用虚拟线程的此类应用程序在ProjectLoom的实验构建中获得了巨大的性能提升。基于早期访问Java 17,这些构建现在可用。项目团队寻求反馈

使用虚拟线程非常简单:切换您选择的执行器服务

ExecutorService executorService = Executors.newVirtualThreadExecutor() ;
警告:JVM管理的虚拟线程依赖于主机操作系统管理的平台/内核线程。最终,执行由操作系统安排,即使在绝缘层下也是如此。当阻塞的Java线程在CPU内核上处于空闲状态时,虚拟线程非常有用。如果主机负载过重,Java线程可能会看到很少的执行时间,无论是否有虚拟线程

虚拟线程不适合于很少阻塞的任务,而真正阻塞的任务是。例如,编码视频。此类任务应继续使用常规线程

有关更多信息,请参阅Oracle的Ron Pressler或Loom团队其他成员的启发性演示和访谈。随着织机的发展,寻找最新的

我本以为被阻止的线程可以临时重新调度以运行其他提交的任务

这就是其他线程的用途。如果您创建了X个线程,并且Y被阻止,那么您就有剩余的X-Y线程来执行其他提交的任务。据推测,选择数字X是为了获得实现和/或程序员认为最好的并发任务数


您会问为什么实现没有忽略这个决定。答案是,合理地选择线程数量比让实现忽略该选择更有意义。

您部分正确

在您描述的executor服务场景中,所有9个线程都将被阻塞,只有一个线程将取得进展。对

您不太正确的地方在于,您试图期望操作系统和Java的行为结合起来。请参阅,线程的概念存在于操作系统和Java级别。但它们是两种不同的东西。所以有Java线程和OS线程。Java线程是通过操作系统线程实现的

想象一下,JVM中有(比如)10个Java线程,有些正在运行,有些没有。Java借用了一些操作系统线程来实现运行中的Java线程。现在,当一个Java线程被阻塞时(无论出于什么原因),我们可以肯定的是,Java线程已经被阻塞。我们无法轻松观察底层OS线程发生了什么

操作系统可以回收操作系统线程并将其用于其他用途,也可以保持阻塞状态,这取决于具体情况。但即使操作系统线程被重用,Java线程仍然会被阻塞。在线程池场景中,仍然会阻塞九个Java线程,并且只有一个Java线程工作

如果有一个线程在等待锁定时被阻塞,操作系统是否可以重新安排该线程执行其他工作,直到锁定可用?根据我的理解,它不能被重新调度,它只是在获得锁之前处于空闲状态。但这似乎效率低下

我认为你认为这是完全错误的。仅仅因为20个线程中有10个是“空闲”的,并不意味着操作系统(或JVM)正在以某种方式消耗资源来管理这些空闲线程。虽然一般来说,我们在应用程序上工作以确保线程尽可能无阻塞,从而实现最高吞吐量,但我们编写线程的次数很多,而我们期望它们大部分时间处于空闲状态

如果有100个任务提交给ExecutorService,并且池中有10个线程:如果其中一个线程持有锁,而其他9个线程正在等待该锁,那么只有持有锁的线程才能取得进展。我本以为被阻止的线程可以临时重新调度以运行其他提交的任务