当单个程序有多个 `ThreadPoolExecutor` 时会发生啥?

Posted

技术标签:

【中文标题】当单个程序有多个 `ThreadPoolExecutor` 时会发生啥?【英文标题】:What happens when a single program has multiple `ThreadPoolExecutor`s?当单个程序有多个 `ThreadPoolExecutor` 时会发生什么? 【发布时间】:2020-06-13 09:18:21 【问题描述】:

ThreadPoolExecutor 实例管理线程:它负责将其队列中的任务匹配到一定数量的线程。

鉴于线程是公共资源,直观地说它们应该由每个应用程序的“一个管理器”管理。

但是,存在“最佳实践”告诉您为某些场景创建多个执行器。例如,有人认为您应该创建两个独立的执行器,一个用于 CPU 密集型任务,另一个用于阻塞 IO 任务。

为什么会这样?

直观地说,让多个“管理器”管理同一组线程,而不知道彼此的存在对我来说听起来像是一种反模式。

JVM 是否知道多个执行器的存在并执行额外的管理以确保它们不会争夺同一个线程?

【问题讨论】:

【参考方案1】:

我真的建议你看看“Java 并发实践”一书。

仅引用第 8 章的部分内容:

当任务同质且独立时,线程池效果最佳。混合长时间运行和短期运行的任务有“堵塞”池的风险,除非它非常大;除非池是无限的,否则提交依赖于其他任务的任务有死锁的风险。

...

如果任务可以长时间阻塞,线程池可能会出现响应问题,即使死锁是不可能的。线程池可能会被长时间运行的任务堵塞,即使是短期任务也会增加服务时间。如果池大小相对于长期运行任务的预期稳态数量而言太小,最终所有池线程都将运行长期运行任务并且响应能力将受到影响。

通过将长时间运行的 IO 任务和快速 CPU 任务分成两个不同的线程池,您可以缓解此问题。线程池不会争夺同一个线程,因为它们不共享任何线程。

【讨论】:

我是否正确,理想情况下,如果任务受 CPU 限制,分配给 每个 执行程序的线程总数不应超过 CPU 总数?我故意从等式中排除考虑 IO 绑定任务,以保持问题简单。例如,在 16 核机器中,我最多应该有两个大小为 8 的 ThreadPoolExecutor,而不是更多。因为否则应用程序中会有更多线程导致不必要的上下文切换? 好吧,不需要 N_threads

以上是关于当单个程序有多个 `ThreadPoolExecutor` 时会发生啥?的主要内容,如果未能解决你的问题,请参考以下文章

在单个 AppDomain 上运行多个应用程序实例时如何防止属性覆盖?

当条件多个布局应用于单个活动时管理单个数据绑定对象

在单个页面上制作一个应用程序的多个不同副本(AngularJS)

iOS8 - 多个目标的单个小部件

多个视图的单个相机视图

在单个应用程序中打开多个 websocket 连接