【问题标题】:Is it safe to have multiple Executors.newCachedThreadPool() in a Java program?在 Java 程序中拥有多个 Executors.newCachedThreadPool() 是否安全?
【发布时间】:2019-12-14 13:06:56
【问题描述】:

此方法的规范:https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html#newCachedThreadPool()

创建一个线程池,根据需要创建新线程,但在可用时将重用以前构造的线程。这些池通常会提高执行许多短期异步任务的程序的性能。如果可用,对执行的调用将重用以前构造的线程。如果没有可用的现有线程,将创建一个新线程并将其添加到池中。六十秒内未使用的线程将被终止并从缓存中删除。因此,保持空闲足够长时间的池不会消耗任何资源。请注意,可以使用 ThreadPoolExecutor 构造函数创建具有相似属性但细节不同(例如超时参数)的池。

从这个描述中我不清楚 - 在一个程序中拥有多个这样的池是否安全?或者我是否可能会遇到一个池在多个线程上停滞并冻结其他池的情况?

【问题讨论】:

  • 您为什么希望一个池冻结另一个池?除了线程饥饿(过度使用共享资源)之外,它们不会对彼此产生任何影响。
  • 对这些东西不太熟悉,但我认为你提到的“其他”是我担心的。如果我为每个池指定固定数量的线程,那么我可以保证我不会用完线程,对吧?但是如果我使用这个缓存池,如果一个池将它们全部占用并卡在它们上面,我可能会用完其他池的线程吗?
  • 您可以创建的线程数实际上并没有硬性限制。但是,当您创建更多它们时,它们的效率会降低。
  • 此外,每个线程都有一个堆栈并使用内存(对于典型的 64 位 JVM,默认为 1MB),如果你 start() 太多,你可能会得到一个 OOME。
  • Java 线程(大约 20 年)由本机线程支持;本机线程由操作系统管理。

标签: java multithreading concurrency threadpool


【解决方案1】:

我认为对此没有明确的是/否答案。

一方面,ThreadPoolExecutor 实例消耗的线程数量不是有限的。 JVM架构本身不限制线程数。

另一方面,操作系统/环境可能会设置一些限制:

  • 操作系统可能对其支持的本机线程总数有硬性限制。

  • 操作系统可能限制给定进程(在本例中为 JVM)可以创建的本机线程数。这可以使用ulimitcgroup 限制以及可能的其他方式来完成。

  • 在典型的 64 位 JVM 上,Java 线程堆栈的大小为 1MB(默认情况下)。如果您尝试 start() 过多线程,您可能会耗尽内存并获得 OOME。

  • 如果有足够多的线程和/或过多的线程上下文切换,线程调度程序(在操作系统中)可能会遇到问题。

    (上下文切换通常发生在线程执行阻塞系统调用或必须等待锁定或通知时。每次切换上下文时都会产生与硬件相关的开销:保存和恢复寄存器、切换虚拟内存上下文、刷新内存缓存等)

另一方面,除了线程池的数量和大小之外,还有其他因素可能导致问题。例如,如果线程任务相互交互,您可能会遇到以下问题:

  • 锁定共享对象时出现死锁,
  • 共享锁争用过多会导致资源匮乏,
  • 工作量过多导致超时,或者
  • 优先级反转问题...如果您尝试使用优先级来“管理”工作负载。

所以...

在一个程序中包含多个这样的池是否安全?

或者我可能会遇到一个池在多个线程上停止并冻结其他池的情况。

除非任务以某种方式进行交互,否则您不太可能会遇到“停顿”。

但是,如果您有太多的可运行线程竞争 CPU,每个线程将(平均)获得有限数量的可用内核的较小份额。锁争用或过多的上下文切换会进一步减慢速度。

【讨论】:

    猜你喜欢
    • 2014-03-29
    • 2011-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-19
    相关资源
    最近更新 更多