[ Java ]中的线程池工作原理,为什么不是先创建线程而是先往阻塞队列里塞任务?

49 天前
 lsk569937453

假设核心线程数为 n,最大线程数为 m 。线程池创建后,就提交了 n 个任务且这 n 个任务一直在执行,没有结束。此时再提交一个任务就会塞到任务队列里。我的疑问是新提交的这个任务为什么不是创建一个新的线程执行?。线程池不是应该首先要保证任务完成吗?

现在的逻辑是"先判断任务队列是否满再判断是否达到最大线程数",这样设计有什么优点呢?

5672 次点击
所在节点    Java
86 条回复
lyxeno
49 天前
我的理解是资源有限的情况,无限增加并行的线程并不会使得任务处理速度更快,反倒会因为线程上下文切换和线程的创建销毁导致额外的开销。

使用线程池一个很重要的原因就是节省资源。你如果不需要节省资源,直接自己创建线程不就好了。
lsk569937453
49 天前
@veapon 有什么就说什么,如果你不懂可以不说。做技术的不要拿反问句回答别人。
salmon5
49 天前
tomcat 的线程池逻辑就是合理的:核心线程不够了,直接申请新创建线程。而不是先扔到队列。
LiaoMatt
49 天前
我觉得是因为任务应该很快就可以被处理, 在队列里留存的时间很短, 所以可以先不创建新的线程, 直到队列满了表现出线程池的计算能力真的不够用了, 再启动线程去消费队列, Doug Lea 觉得这样处理适用于大部分场景吧
salmon5
49 天前
@salmon5 #17 ,假如一台 CPU 64C 混部的机器,CPU 只用了 20C ,还有 44C ;
1 个 Java 核心线程是 10 ,放着 44C 不用,不够了居然放到了队列,这种线程池逻辑明显落后了。
codegenerator
49 天前
@lsk569937453 很简单你增加 n 到 m 就解决了
whileFalse
49 天前
因为它就是这么设计的,最大线程数相比核心线程数多出来的那一点是为了给任务队列兜底的
如果你不喜欢,可以把核心线程数设为和最大线程数一致,应该就可以满足你的需求了
veapon
49 天前
还有个场景,当任务超过 n 时,如何保证任务按指定规则创建线程执行?这个是不是也是用队列的一个场景。
muyiluop
49 天前
@salmon5 #25 为啥创建的时候不直接创建一个核心线程数是 64 的呢。就像我们目前基本都是核心线程数直接是 cpu 核数。
salmon5
49 天前
“先判断是否达到最大线程数在判断任务队列是否满了”,我推测 因为这个逻辑是 199 几年或者 200 几年弄的,那时候云计算或者硬件资源都相当有限,所有这个逻辑有点落后了。
leonshaw
49 天前
按 op 的需求想一下如何实现,感觉在提交任务时并不能很容易地判断是不是所有线程都繁忙。
salmon5
49 天前
@muyiluop 混合部署省钱,64C256G/128G 可以部署十几、几十个微服务,不是每一个服务都每一刻这么大并发,需要的时候就申请,很多服务 tps 个位数,初始线程不需要那么多。(但是你核心线程不够了,可以马上申请创建,而不是弄个队列,自废武功)
whileFalse
49 天前
另外 lz 的问题,就算应用已经启用了最大线程数,这些线程都被占满了怎么办?我不是杠,而是如果你的有两种任务,一种很快另一种几乎无法完成,那么不管你有多少线程很快都会被后者占满

这是你架构设计的问题,长时间的工作不要和其他工作共享线程池,你可以考虑把这些很慢的工作抽离出来放到单独的 job 服务里面,然后按照需求调整“快任务”服务和“慢任务”服务的数量
whileFalse
49 天前
@salmon5 那你能解释一下你这个核心线程到底有什么用吗
LiaoMatt
49 天前
假设的有十个并发任务需要处理, 每个任务需要 10ms, 当前核心线程池是 5, 用队列的理想时间是 20ms, 不需要创建销毁线程, 如果立马增加 5 个线程, 处理的理想时间大概是 10ms, 空闲后需要销毁, 如果类似的场景很多, 就需要频繁的创建销毁, 用队列可以做到削峰平谷, 避免以上场景造成的线程创建销毁的开销
salmon5
49 天前
合理:核心线程---->不够了创建新线程--->队列( Tomcat )
不合理:核心线程---->队列满了--->创建新线程( Java )
salmon5
49 天前
@LiaoMatt #35 这个貌似 Java 的又合理了。
iosyyy
49 天前
线程池要保证的不是任务的完成而是任务的调度 保证大部分任务都能完成并且给予一定的容错才是线程池应该做的
所以为什么不能先达到最大线程已经很明显了 先达到最大线程不满足调度的需求这部分最大线程的资源被白白浪费掉了

另外建议阅读提问的艺术你这是提问的语气?
Rickkkkkkk
49 天前
要不发邮件问问作者
perbugwei
49 天前
@TuringHero
我觉得这个是正解,这种池化的思想 是为了解决创建连接的开销,线程池和数据库连接池,都是为了避免频繁的销毁和创建。所以先放到队列中,然后再判断是否到最大线程数,是为了延迟创建线程。op 的“保证任务完成 ”,这个不是线程池做的事,是想要通过多线程的方式来实现,这个涉及到具体的业务场景了,需要开发的时候具体处理的。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1036271

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX