➡️ 程序员曜灵 · 后端面试追问链 - 欢迎认识我作者程序员曜灵,绿泡泡「我要拿offer」和小红书同名。主业在一家大型央企做后端开发,Java 方向,参与过公司内部招聘面试。这里在拆高频面试题的追问链,一题三层,每层给及格线答案和大多数人挂在哪。工作日每天一篇,评论区点最高频的问题决定下一篇写什么。线程池这题我一般让人先讲七个参数。讲完 corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue、threadFactory、handler,再背一遍四种拒绝策略,时间过去六分钟,内容全对。然后我问一句,你这个 workQueue 用什么。答LinkedBlockingQueue的占大多数。我接着问,那 maximumPoolSize 什么时候生效。到这里就断了。因为在你刚说的那个配置下,它永远不生效。无界队列把 maximumPoolSize 变成摆设java.util.concurrent.ThreadPoolExecutor的 Javadoc 在 Queuing 一节的 Unbounded queues 段落里写得挺直白。Thus, no more than corePoolSize threads will ever be created. (And the value of the maximumPoolSize therefore doesn’t have any effect.)前面还有一句解释为什么。无界队列永远不会满,所以队列满了才创建非核心线程这个条件永远不成立。这一句顺带解释了两件事。Executors.newFixedThreadPool为什么叫固定大小线程池,因为它内部就是无界LinkedBlockingQueue,maximumPoolSize 传进去等于没传。也解释了为什么固定池加无界队列其实是同一个坑的两种说法,队列会一直堆积任务直到 OOM,而线程数永远停在 corePoolSize。要让 maximumPoolSize 真的起作用,队列必须有界。用new ArrayBlockingQueue(capacity)建池,队列满了才会往 core 之外扩线程,扩到 maximumPoolSize 再触发拒绝策略。corePoolSize 那句永不销毁有个例外很多文章写核心线程即使没有任务也保持存活。Javadoc 的原文后面还挂着半句。corePoolSize - the number of threads to keep in the pool, even if they are idle, unlessallowCoreThreadTimeOutis setallowCoreThreadTimeOut(boolean)一旦设成 true,keepAliveTime 就开始管核心线程,空闲的核心线程也会被回收。低峰期线程数能掉到零。keepAliveTime 默认碰不到核心线程同一段 Javadoc 里,keepAliveTime 的定义前面有个限定从句。keepAliveTime - when the number of threads is greater than the core, this is the maximum time that excess idle threads will wait for new tasks before terminating.when the number of threads is greater than the core。默认情况下这个参数只对超出 core 的那部分线程生效。把keepAliveTime 是线程空闲多久后销毁当成完整答案,少了一个前提。现在说一个正在过时的规矩阿里巴巴 Java 开发手册里那条【强制】写的是不允许使用Executors创建线程池,要走ThreadPoolExecutor,理由是资源耗尽。手册说明分两条,FixedThreadPool和SingleThreadPool的请求队列允许Integer.MAX_VALUE,CachedThreadPool和ScheduledThreadPool的创建线程数允许Integer.MAX_VALUE。这条规约本身没错,它针对的是无界带来的内存风险。但它和 JDK 21 之后的官方建议撞上了。JEP 444(Virtual Threads,状态 Closed/Delivered,目标 JDK 21)给出的迁移入口就是工厂方法。Executors.newVirtualThreadPerTaskExecutor()同一份 JEP 里还有一句。Virtual threads are not expensive so there is never a need to pool them.虚拟线程不贵,所以永远不需要池化它们。规约说别用Executors,JDK 官方文档给的虚拟线程方案就叫Executors.newVirtualThreadPerTaskExecutor()。字面上打起来了。真要回答这个问题,得分场景。平台线程时代规约成立,因为线程是稀缺资源,池化的目的是复用和限流。虚拟线程时代池化这件事本身被官方否定了,需要限流的场景 JEP 444 建议用Semaphore,举的例子是某服务只能承受 20 并发。一张表把默认值和出处钉住说法实际出处队列满了才创建非核心线程仅在有界队列下成立;无界队列下 maximumPoolSize 无效ThreadPoolExecutorJavadoc,Queuing核心线程永不销毁除非设置了allowCoreThreadTimeOut同页构造参数说明keepAliveTime 是线程空闲存活时间仅当线程数大于 core 时生效同页构造参数说明禁止使用 Executors 创建线程池阿里手册【强制】,针对资源耗尽p3c 仓库p3c-gitbook/编程规约/并发处理.md虚拟线程需要池化JEP 444 明确说永远不需要openjdk.org/jeps/444面试里我会怎么分层第一层,七个参数和四个拒绝策略背齐。这是看过资料的证明,不加分。第二层,能说出无界队列下 maximumPoolSize 无效,并且知道要换ArrayBlockingQueue。到这一层我确认他写过配置,不是只背过定义。第三层,我问他线上线程池参数怎么定的。答IO 密集设 2N、CPU 密集设 N1的,我会追问这个公式哪来的。它出自《Java并发编程实战》的N_threads N_cpu × U_cpu × (1 W/C),博客版本把目标利用率U_cpu整个丢掉了,而 W/C 这两个数必须实测。说不出实测方法的,这个 2N 就是抄来的。第四层,能主动提虚拟线程和规约的冲突。这种人不常见,通常说明他在跟 JDK 21 之后的东西。出处三段 Javadoc 原文引自 OracleJava SE 21平台文档java.util.concurrent.ThreadPoolExecutor,2026-10-10 用 WebFetch 逐字核对,Java SE 25同路径也可访问。JEP 444 的编号、状态、目标版本和两句原文引自openjdk.org/jeps/444。阿里规约条目和说明文字取自 p3c 仓库的 gitbook 文本,由协作调研核对;gitbook 是早期版本,条号和【强制】标记请以你手上的《Java开发手册》正式版本再对一次。N_threads公式出自《Java并发编程实战》8.2.2 节,这一条我没有找到可访问的线上原文,按原书章节引。你如果要在面试里说这个公式,建议手边有书再讲,别只记结论。最后如果觉得这篇有用,可以点赞收藏关注 支持一下,程序员曜灵的主页还有很多按追问链拆的面试题,欢迎前去点评。哪里讲得不准,评论区指出,我改在这篇的更新里。欢迎学习交流、面试问题求助、共同进步。绿泡泡【我要拿offer】,回复 Java 拿那份按模块整理的高频面试题 PDF。想看每日面经和 offer 案例的,小红书同名号程序员曜灵。