2

我正在使用 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 命令查看内存使用情况。对于时间,我们以毫秒为单位放置 System.currentTime 的记录器来检查使用情况。

请告诉如何优化这个设计。谢谢。

4

2 回答 2

3

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

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

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

通常我们使用这些ExecutorService类不一定是因为它们比原始线程更快,而是因为代码更易于管理。并发类可以处理很多锁定、排队等问题。

几个代码注释:

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

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

  • 我从来不用pool.prestartAllCoreThreads();. 一旦任务被提交到池中,核心线程就会启动,所以我认为它不会给你带来太多好处——至少对于长时间运行的应用程序来说不会。

对于时间,我们以毫秒为单位放置 System.currentTime 的记录器来检查使用情况。

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

于 2013-10-04T16:02:09.347 回答
0

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

听起来您在其他地方遇到了瓶颈。您是否锁定单个对象?您是否有每个线程都命中的单个单线程资源?在这种情况下,您不会看到任何行为变化。

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

于 2013-10-04T16:02:26.347 回答