【发布时间】:2018-04-02 17:45:01
【问题描述】:
多年来我一直使用 ThreadPoolExecutors,其中一个主要原因 - 由于并行性和“准备就绪”线程(虽然还有其他线程),它旨在“更快”处理许多请求。
现在我只关注以前众所周知的内部设计。
这是来自 java 8 ThreadPoolExecutor 的 sn-p:
public void execute(Runnable command) {
...
/*
* Proceed in 3 steps:
*
* 1. If fewer than corePoolSize threads are running, try to
* start a new thread with the given command as its first
* task. The call to addWorker atomically checks runState and
* workerCount, and so prevents false alarms that would add
* threads when it shouldn't, by returning false.
*/
...
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
...
我对这第一步很感兴趣,因为在大多数情况下,您不希望线程轮询执行器将“未处理的请求”存储在内部队列中,最好将它们留在外部输入 Kafka 主题/JMS 队列等中。因此,我通常将面向性能/并行性的执行器设计为具有零内部容量和“调用者运行拒绝策略”。您选择了一些合理的大量并行线程和核心池超时,而不是吓到其他人并显示价值有多大;)。我不使用内部队列,我希望任务越早开始处理越好,因此它已成为“固定线程池执行器”。因此,在大多数情况下,我处于方法逻辑的“第一步”之下。
问题来了:它真的不会“重用”现有线程,而是每次“低于核心大小”时都会创建新线程(大多数情况下)吗? “只有在所有其他人都很忙时才添加新的核心线程”而不是“当我们有机会在另一个线程创建上吸一会时”不是更好吗?我错过了什么吗?
【问题讨论】:
-
我不可能是唯一一个阅读 DeadPoolExecutor 的人
-
只有当您的“corePoolSize”非常大(大于您曾经处理的请求数)时,您才在第一步。这是因为每个启动的工作人员的工作人员计数都会增加(并且只有在线程停止时才会减少)
-
我处于第一步,因为负载一直在“波动”,并且由于“核心线程超时”而等待线程退出。此外,负载通常不会那么大,需要创建所有核心线程。所以我可以看到这张图片:在 20 个核心线程中,它使用了 10 个,并且对于每个新提交它都会创建新线程,旧线程会因为超时而退出。
-
不太明白这个问题 - 当然 它会创建它们 - 如果核心线程不存在 someone 必须创建然后.当线程都忙,并且您低于最大计数时,它也会创建一个新线程。不同之处在于,核心线程一直存在,直到池关闭并且其他线程有空闲超时。
-
在你明白了这一点之后,投票赞成/反对通常是明智的......
标签: java multithreading