优化线程池执行器-java

时间:2013-10-04 15:54:31

标签: java multithreading concurrency executorservice

我使用ThreadPoolexecutor将其替换为传统的Thread。

我创建了执行程序如下:

pool = new ThreadPoolExecutor(coreSize, size, 0L, TimeUnit.MILLISECONDS,
       new LinkedBlockingQueue<Runnable>(coreSize),
       new CustomThreadFactory(name),
       new CustomRejectionExecutionHandler());
pool.prestartAllCoreThreads();

此核心大小为maxpoolsize / 5。我已经预先启动了大约160个线程的应用程序启动时的所有核心线程。

在传统设计中,我们创建并启动了大约670个线程。

但关键是即使在使用Executor并创建和替换传统设计之后,我们也没有获得更好的结果。

对于结果内存管理,我们使用top命令查看内存使用情况。 有一段时间我们用millis放置System.currentTime的记录器来检查用法。

请告诉我们如何优化此设计。感谢。

2 个答案:

答案 0 :(得分:3)

  

但关键是即使在使用Executor并创建和替换传统设计之后,我们也没有获得更好的结果。

我假设您正在查看应用程序的整体吞吐量,并且您没有看到更好的性能,而不是在自己的线程中运行每个任务 - 即没有池?

这听起来像是因为上下文切换而没有被阻止。也许你的应用程序是IO绑定或等待其他系统资源。 670个线程听起来很多,你可能会使用大量的线程堆栈内存,但它可能没有阻碍你的应用程序的性能。

通常我们使用ExecutorService类不一定是因为它们比原始线程更快,但因为代码更容易管理。并发类可以解决大量锁定,排队等问题。

情侣代码评论:

  • 我不确定您希望LinkedBlockingQueue受核心大小的限制。这是两个不同的数字。 core-size是池中的最小线程数。 BlockingQueue的大小是可以排队等待免费线程的作业数量。

  • 顺便说一句,ThreadPoolExecutor永远不会分配线程超过核心线程号,除非 BlockingQueue已满。在您的情况下,如果所有核心线程都忙,并且队列已满,核心大小的排队任务数是在分叉下一个线程时。

  • 我从来没有使用pool.prestartAllCoreThreads();。一旦将任务提交到池中,核心线程就会被启动,所以我认为它不会给你带来太大的收益 - 至少不是长期运行的应用程序。

  

有一段时间我们将mill.c的System记录器放在millis中以检查用法。

小心这一点。太多的记录器可能会影响应用程序的性能,而不是重新构建它。但是我假设您在之后添加了记录器,但没有看到性能提升。

答案 1 :(得分:0)

执行程序只包装了Threads的创建/使用,所以它没有做任何神奇的事情。

听起来你在别处有瓶颈。你是否锁定了一个对象?每个线程都有一个单线程资源吗?在这种情况下,您不会看到任何行为上的任何变化。

您的进程是否受CPU限制?如果是这样,你的线程(非常粗略地说)应该与可用的处理核心数相匹配。请注意,您创建的每个线程都会为其堆栈消耗内存,如果您受内存限制,那么创建多个线程将无助于此。