下面的场景已简化
服务器是 4 核 Intel(无超线程)Linux 服务器、Java 11 Server 64 VM。我们有一个 ThreadPoolExecutor,其 maxSize 为 15 个线程。
一种使用 Executor 的方法提交 4 个 Callables,执行长时间运行的数据库调用,另一种方法使用 Executor 提交另外 10 个执行非常快速计算的 Callables。 前 4 个线程获取 CPU 时间,然后阻塞等待查询返回。 我的问题有两个 - DB 调用是否类似于阻塞 I/O,当提交新的 Callables 并分配线程时,这些线程是否会开始运行,而其他线程正在等待 DB 调用返回,或者它们是否会排队? 我知道有很多变量我没有在这里讨论,请指出它们是否相关,但我认为基本问题非常清楚。
数据库调用是否与阻塞 I/O 类似
是的,涉及 JDBC 的调用会阻塞,从而暂停 Java 线程下的主机 OS 线程。至少目前在 Java 11 以及 Java 17 和 20 中是这样。
如果Project Loom成功,这一事实可能会改变。
当新的 Callable 被提交并分配线程时,这些线程是否会开始运行,而其他线程正在等待数据库调用返回,或者它们是否会排队?
如果支持执行程序服务的线程池中的所有线程都被阻塞,或者处于繁忙/占用状态,则挂起的任务将与任何其他已提交的任务一样排队。这个排队是执行器服务的主要工作。
再次强调,Loom 项目及其虚拟线程(从技术上讲,纤维)旨在改变这种情况。
服务器是 4 核 Intel(无超线程)……最大大小为 15 个线程
您是否怀疑较短的简单调用堆积在占用所有线程的长阻塞数据库调用后面?就像高速公路上一些小型快速通勤车被困在大型慢速半挂卡车车队后面一样?
如果是这样,请考虑实例化 two 执行器服务。
我要强调的是,本答案的未来读者应该检查 Java 20 之后 Project Loom 的进展更新。如何管理线程的计算将发生巨大变化。
如果我将问题读作:
答案是否定的。
这与 Java 无关,这是关于 操作系统调度。 (所以从技术上讲,答案取决于您的操作系统,但它们长期以来都在执行多任务)
因此,在您的精确示例中,在 15 个线程池大小的执行器服务上,您的 10 个“快速”任务将很好地完成,而您的 4 个“长 I/O 阻塞”任务仍在“处理”中。 (无论CPU/核心的物理数量,或Java版本)