【问题标题】:Java Multithreading - Starting a lot of threads and keeping them idle, vs lazy loading new threads?Java多线程 - 启动大量线程并保持它们空闲,与延迟加载新线程?
【发布时间】:2013-10-14 05:30:00
【问题描述】:

我的情况是,我有 4 组,每组 7 个线程。我的 CPU(核心 i7)应该能够处理 8 个线程,所以我正在考虑一次通过每个组,运行 7 个线程,然后移动到第二组,运行它的 7 个线程,然后是第三和第 4 组以同样的方式,然后从第 1 组开始,直到用户发送停止命令。

我的问题是,一旦每组 7 个线程完成处理,我应该让这些线程保持空闲状态,还是完全关闭它们并在下一次迭代时重新启动一组新的 7 个线程?哪种方法会更快?这是一个速度非常密集的应用程序,所以我需要一切都尽快发生。

我将使用FixedThreadPool 来管理每组 7 个线程。所以我可以只使用invokeAll(),然后让它们不管(大概是空闲),或者我可以shutdown()invokeAll() 之后的每个线程池,并在下一次迭代时启动一个新的线程池。

哪种方法会更快?

【问题讨论】:

  • 我不明白,线程池应该能够为你处理所有细节

标签: java multithreading performance optimization threadpool


【解决方案1】:

我的问题是,一旦每组 7 个线程完成一个处理周期,我应该让这些线程保持空闲状态,还是完全关闭它们并在下一个周期重新启动一组新的 7 个线程?

我会使用单个ExecutorService 线程池,并为所有 任务重用相同的线程。请参阅tutorial on the subject。线程池旨在执行任何RunnableCallable 类,因此它们与任务无关。例如,您可能有 ParentResultChildResult 类。您可以将Callable<ParentResult> 提交到将返回Future<ParentResult> 的线程池并且您可以将Callable<ChildResult> 提交到将返回Future<ChildResult> 的同一线程池。 p>

您想要拥有“线程组”的唯一原因是每个线程都有一些必须维护的状态——数据库连接或其他东西。即便如此,仍有许多人使用线程池,因为它为您完成了大部分并发繁重的工作。

如果您必须保持此状态,那么我肯定不会关闭池,然后再重新启动它们。休眠线程/池除了内存之外没有占用任何系统资源。您这样做的唯一原因是,如果您为该任务分叉了 100 个线程,但此时您应该考虑重新构建您的应用程序。

【讨论】:

  • 谢谢。我需要有 4 组线程,因为每个组将处理一个特定的项目。所以前 4 组将返回 Future<ParentResult>,后 24 个线程将返回 Future<ChildResult>ChildResults 将全部由 ParentResult 聚集在一起,然后才会传递最终的 Result..跨度>
  • 线程池与@ClickUpvote 返回的Future 无关。您可以(并且应该)将 Callable<ParentResult>Callable<ChildResult> 提交到 same 线程池。
  • 我不知道。谢谢
  • 当我们谈到这个话题时,你能告诉我,如果在线程池上调用shutDownNow(),而它仍然有一些正在处理的Callable 项目会发生什么?我在可调用对象中没有run() 方法,所以我不知道它们是否会立即被中断或允许完成
  • shutdownNow() 将尚未运行的任务出列并中断正在运行的线程。这并不意味着这些线程将停止,除非它们正在寻找中断。看到这里@ClickUpvote:stackoverflow.com/questions/9791361/thread-not-interrupting/…
【解决方案2】:

您无需手动安排线程。一次启动所有 28 个线程 - 这不会更慢,但可以更快。

【讨论】:

    【解决方案3】:

    当您说您的处理器有 8 个线程时,我认为您的意思是它有 4 个带有超线程的内核。 Java 使用的线程与您的处理器不同,因此这 7 个线程的类型与您的处理器不同。

    JVM 处理处理器使用情况,并且 (IIRC) 仅限于使用 1 个内核。 java 使用的线程特定于 JVM,并且是完全独立的。

    至于您的实际问题,请尝试测试不同的线程组合,看看哪个最快,这将为您提供比扶手椅理论更准确的答案。

    【讨论】:

    • 您是对的,但这是评论,不回答问题。
    • 所以JVM不能利用多核?它仅限于 1 个线程?
    • 它仅限于一个处理器线程,它可以在其中运行多个JVM线程。
    • 为什么你认为JVM只能使用单核?这在很多年前可能是正确的……如果现在是真的,为什么会有人将 Java 用于服务器?
    【解决方案4】:

    我也更喜欢Alexei Kaigorodov 建议启动所有 28 个线程。但我建议你用新的Executors API 替换newFixedThreadPool:(从Java 8 开始)

    static ExecutorService  newWorkStealingPool()
    

    使用所有可用处理器作为目标并行级别创建一个工作窃取线程池。

    以上API返回ForkJoinPool类型的ExecutorService

    现在您无需担心空闲线程的利用率。 Java 将通过工作窃取机制更好地利用空闲线程。

    如果您仍然需要四组不同的 FixedThreadPools,您可以继续使用invokeAll。不要关闭 ExecutorService 在多个池之间切换。你一个ExecutorService 有效。如果要使用invokeAll 轮询Future 任务的结果,使用CompletableFuture 并轮询它以了解任务执行的状态。

    static CompletableFuture<Void>  runAsync(Runnable runnable, Executor executor)
    

    返回一个新的 CompletableFuture,它在运行给定操作后由给定执行器中运行的任务异步完成。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-10-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多