阻塞在大多数基于业务的应用程序中非常常见。阻塞发生在文件I/O、网络I/O、数据库访问、日志记录、控制台交互、GUI等方面。使用虚拟线程的此类应用程序正在实验性构建的Project Loom中看到巨大的性能提升。这些构建现在可用,基于Java 17的早期访问版本。Project Loom团队正在寻求反馈。
使用虚拟线程非常简单:切换您选择的执行器服务。
ExecutorService executorService = Executors.newVirtualThreadExecutor() ;
注意:正如Michael所评论的那样,JVM管理的虚拟线程取决于主机操作系统管理的平台/内核线程。最终,即使在Loom下,执行也由操作系统调度。当阻塞的Java线程在CPU核心上空闲时,虚拟线程非常有用。如果主机计算机负载过重,Java线程可能会看到很少的执行时间,无论是否使用虚拟线程。
对于很少阻塞、真正CPU密集型的任务,虚拟线程不适合。例如,视频编码。这些任务应该继续使用传统的线程。
有关更多信息,请参阅Oracle的Ron Pressler或Loom团队的其他成员的启发性演示和采访。寻找最新的版本,因为Loom已经发展。
这就是其他线程的作用。如果你创建了X个线程,其中Y个被阻塞,你仍然有剩余的X-Y个线程去完成其他提交的任务。可以推测,选择数量X是根据实现和/或程序员的想法得出的并发任务数量最佳值。
你想知道为什么实现不忽略这个决策。答案在于选择合适的线程数量比让实现忽略该选择更有意义。
你的部分说法是正确的。
在你描述的执行器服务场景中,所有9个线程都将被阻塞,只有一个线程会取得进展。没错。
你不太正确的地方在于试图预期操作系统和Java结合的行为。看,线程的概念存在于操作系统和Java级别。但它们是两个不同的东西。因此,有Java线程和操作系统线程。Java线程是通过操作系统线程实现的。
这样想象,JVM中有(假设)10个Java线程,有一些正在运行,有一些没有。Java借用一些操作系统线程来实现正在运行的Java线程。现在当Java线程被阻塞(无论出于何种原因),我们可以确定的是Java线程已被阻塞。我们不能轻易观察底层操作系统线程发生了什么。
操作系统可以回收操作系统线程并将其用于其他用途,也可以保持阻塞状态——这取决于情况。但即使操作系统线程被重用,Java线程仍将保持阻塞状态。在您的线程池场景中,仍然有9个Java线程被阻塞,只有一个Java线程在工作。