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

149 天前
 lsk569937453

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

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

6871 次点击
所在节点    Java
86 条回复
Karte
148 天前
为什么这人提问有种高高在上的感觉?
cheng6563
148 天前
@jimrok 这问题现在看来确实很奇怪,和类似的其他场景比如连接池规则都不一样,而且创建连接的消耗可比创建线程高多了。
jimrok
148 天前
@cheng6563 线程池的作用还是为了减少创建线程的开销,在 linux 下是存在用户态和核心态的指令差别的,核心态运行在 cpu 0 的指令级别上,是一种高优先级的程序指令,通常叫系统调用,这些指令能干很危险的操作,例如对物理内存的访问。而用户态只能看到虚拟内存了,这就倒是创建线程时候,会在两个状态的代码之间来回切换。当你做高并发的应用时,例如 1000req/s 的操作时,你就不能忽视这种开销了。你可以做个实验,当你创建 100 万个 thread 对象,即便都在线程池中什么任务都不干,机器已经卡的不行了。
Aresxue
141 天前
因为线程是非常宝贵的资源,这个设计主要就是保证线程资源的最大化利用。

在更早的时候操作系统的可支撑线程数是非常有限的,单机的性能也很弱,但随着时代的发展其实这个思路已经并没有那么适用了,在实际中很多都是把核心数和最大线程数设为一致。更有甚者 tomcat 直接修改了这一策略,在没有可用线程时它会优先开启一个新的线程直至最大线程数,然后才会堆积请求。如今 tomcat 的这种思路更为流行比如 Druid 的连接池中的最小连接数和最大连接数也是这个逻辑。

当然随着虚拟线程的流行,线程的限制将会荡然无存,线程池也会逐步退出历史舞台,最终只服务于很少的一些场景。
Richared
141 天前
因为 Java 线程一比一啊,资源昂贵。比如你一个月 10w 块,是排队等等让你搬砖还是再招一个 10w 块的帮你?我理解是这样的。
Richared
141 天前
@salmon5 可以直接创建核心线程 64 的啊。我遇到过线程池参数直接就是机器核心数的。

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

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

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

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

© 2021 V2EX