我正在使用ThreadPoolexecutor,将其替换为遗留的Thread。
我创建了如下执行器:
pool = new ThreadPoolExecutor(coreSize, size, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(coreSize),
new CustomThreadFactory(name),
new CustomRejectionExecutionHandler());
pool.prestartAllCoreThreads();
这里的核心大小是最大池大小/5。 我已经在应用程序启动时预先启动了大约 160 个线程的所有核心线程。
在传统设计中,我们创建并启动了大约 670 个线程。
但关键是,即使在使用Executor并创建和替换旧设计之后,我们也没有获得更好的结果。
对于结果内存管理,我们使用 top 命令来查看内存使用情况。为了时间,我们已经将System.currentTime的记录器放置在millis中以检查使用情况。
请告诉如何优化此设计。 谢谢。
但关键是,即使在使用Executor并创建和替换旧设计之后,我们也没有获得更好的结果。
我假设您正在查看应用程序的整体吞吐量,并且与在自己的线程中运行每个任务(即不使用池(相比,您没有看到更好的性能?
这听起来像您没有因为上下文切换而被阻止。 也许您的应用程序受 IO 限制或以其他方式等待其他系统资源。 670 个线程听起来很多,你会使用大量的线程堆栈内存,但除此之外,它可能不会阻碍你的应用程序的性能。
通常,我们使用ExecutorService
类不一定是因为它们比原始线程快,而是因为代码更易于管理。 并发类可以处理很多锁定、排队等问题。
几个代码注释:
-
我不确定您是否希望
LinkedBlockingQueue
受到核心大小的限制。 这是两个不同的数字。 核心大小是池中的最小线程数。BlockingQueue
的大小是有多少作业可以排队等待空闲线程。 -
顺便说一句,
ThreadPoolExecutor
永远不会分配超过核心线程数的线程,除非BlockingQueue
已满。 在您的情况下,如果所有核心线程都繁忙并且队列已满,核心大小的排队任务数是下一个线程分叉时。 -
我从来没有使用过
pool.prestartAllCoreThreads();
. 一旦任务提交到池中,核心线程就会启动,所以我认为它不会给你带来太多好处——至少对于长时间运行的应用程序来说不会。
为了时间,我们已经将System.currentTime的记录器放置在millis中以检查使用情况。
对此要小心。 过多的记录器对应用程序性能的影响可能大于重新构建应用程序。 但我假设您在没有看到性能改进后添加了记录器。
执行器只是包装线程的创建/使用,所以它没有做任何神奇的事情。
听起来你在其他地方遇到了瓶颈。您是否锁定了单个对象?您是否有一个每个线程都命中的单线程资源?在这种情况下,您不会看到行为的任何变化。
您的进程是否受 CPU 限制?如果是这样,您的线程应该(粗略地说(与可用的处理内核数量相匹配。请注意,您创建的每个线程都会消耗其堆栈的内存,如果您受内存限制,则创建多个线程在这里无济于事。