Java多线程 - 启动大量线程并保持空闲,与延迟加载新线程相比?

时间:2013-10-07 15:04:48

标签: java multithreading performance optimization threadpool

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

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

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

哪种方法会更快?

4 个答案:

答案 0 :(得分:4)

  

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

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

你想拥有“线程组”的唯一原因是每个线程都有一些必须维护的状态 - 数据库连接或其他东西。即使这样,很多人也会使用线程池,因为它会为你带来大量的并发性。

如果你必须保持这种状态,那么我肯定会关闭这些池,然后再重新启动它们。除了内存之外,休眠线程/池不占用任何系统资源。您执行此操作的唯一原因是,如果您为此任务分配了100个线程,但在此时,您应该考虑重新设计应用程序。

答案 1 :(得分:1)

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

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

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

答案 2 :(得分:1)

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

答案 3 :(得分:0)

我也更喜欢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,它在运行给定操作后由给定执行程序中运行的任务异步完成。