我使用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的记录器来检查用法。
请告诉我们如何优化此设计。感谢。
答案 0 :(得分:3)
但关键是即使在使用Executor并创建和替换传统设计之后,我们也没有获得更好的结果。
我假设您正在查看应用程序的整体吞吐量,并且您没有看到更好的性能,而不是在自己的线程中运行每个任务 - 即没有池?
这听起来像是因为上下文切换而没有被阻止。也许你的应用程序是IO绑定或等待其他系统资源。 670个线程听起来很多,你可能会使用大量的线程堆栈内存,但它可能没有阻碍你的应用程序的性能。
通常我们使用ExecutorService
类不一定是因为它们比原始线程更快,但因为代码更容易管理。并发类可以解决大量锁定,排队等问题。
情侣代码评论:
我不确定您希望LinkedBlockingQueue
受核心大小的限制。这是两个不同的数字。 core-size是池中的最小线程数。 BlockingQueue
的大小是可以排队等待免费线程的作业数量。
顺便说一句,ThreadPoolExecutor
永远不会分配线程超过核心线程号,除非 BlockingQueue
已满。在您的情况下,如果所有核心线程都忙,并且队列已满,核心大小的排队任务数是在分叉下一个线程时。
我从来没有使用pool.prestartAllCoreThreads();
。一旦将任务提交到池中,核心线程就会被启动,所以我认为它不会给你带来太大的收益 - 至少不是长期运行的应用程序。
有一段时间我们将mill.c的System记录器放在millis中以检查用法。
小心这一点。太多的记录器可能会影响应用程序的性能,而不是重新构建它。但是我假设您在之后添加了记录器,但没有看到性能提升。
答案 1 :(得分:0)
执行程序只包装了Threads的创建/使用,所以它没有做任何神奇的事情。
听起来你在别处有瓶颈。你是否锁定了一个对象?每个线程都有一个单线程资源吗?在这种情况下,您不会看到任何行为上的任何变化。
您的进程是否受CPU限制?如果是这样,你的线程(非常粗略地说)应该与可用的处理核心数相匹配。请注意,您创建的每个线程都会为其堆栈消耗内存,如果您受内存限制,那么创建多个线程将无助于此。