← 每日面试题 学习看板

什么是线程池,如何实现的?

面试题/00java/02Java 并发编程/05线程池相关/什么是线程池,如何实现的?.md

面试记录 2026-09-20

题目:什么是线程池,如何实现的?

难度:low

标签:java/threadpool, general/knowledge

评分:⭐⭐⭐☆☆(3/5)

我的回答

线程池从字面上它是线程的存储池,它是一种池化技术。池化技术本身核心的目的就是对相对耗资源或者建立耗资源的数据资源资源物进行一个缓存,达到重复利用利用资源的目的。线程池的实现本身它是把一些线程先创建出来,然后给,在你使用线程的时候直接从池内获取,达到不让你每次去建立一个新线程的目的。然后这个线程使用了之后,你再把这个线程退回给线程池,后续其他的主线程在使用的时候再从线程池里拿。最终实现线程的复用。然后线程池这以 Java 为主去说吧。Java 的线程池主要定义了几个核心参数。首先是核心线程数,也就是最初这个线程池内会保留常驻的线程会有多少。基本上在你创建了请求过来之后,它就会从常驻的核心线程里边拿数据。然后其次它有最大线程,最大的线程数,也就是说这个线程,线程池,当线程任务比较多的时候,会最大扩展,扩展到多少个线程。当扩展到这个线程之后,是不会再去继续扩展的了,这也就是最大线程数。然后是另外的核心参数,就是任务队列。这个是当你请求的任务线程,核心线程已经占用满了之后,有多少任务存留下来。暂缓放到队列里边,然后等核心线程处理完其他的事务之后,再去从任务队列里拿,然后进行一个交替地去获取任务去执行的一个过程。然后这个过程中需要使用任务队列,这个任务队列就是这个一个核心参数,它里边存放着一些要处理的任务。当任务队列满了之后,才开始扩展非核心线程,去使用后续的那个最大线程数去扩展线程,非核心线程。然后另外的就是拒绝策略,比较核心的拒绝策略,这个拒绝策略主要应对的目的就是,当线程池实在处理不了你这个线程了,实在处理不了你的任务的时候,以什么方式去给你反馈。常见的是直抛异常,就是你你给我发任务,我处理不了了,我就抛一个异常给你,你自己想办法处理,告诉你出问题了。还有就是吞掉,什么都不处理,直接就过掉,把这个任务放弃。另外是可以自定义,还有就是把这个任务放给当前调用的主线程去处理,它自己处理,我不处理。基本上就这些。

点评

优点:

不足:

补充:

  1. 7 大核心参数:corePoolSize / maximumPoolSize / keepAliveTime / unit / workQueue / threadFactory / handler
  2. 执行流程:来任务 → core?→ 队列未满?→ max?→ 拒绝策略(队列优先级高于 max 扩容)
  3. 队列选择:CPU 密集用 SynchronousQueue;IO 密集用 ArrayBlockingQueue 有界
  4. Executors 风险:LinkedBlockingQueue 无界 OOM、CachedThreadPool 线程暴涨
  5. 估算公式:CPU 密集 N_cpu × 1,IO 密集 N_cpu × 2 或 N_cpu × (1 + wait/compute)
  6. 监控指标:queueSize / activeCount / completedTaskCount / rejectedCount(MBean 暴露)

完整讲解

第一部分:知识重点剖析

核心考点定位:考察对 ThreadPoolExecutor 的参数体系、执行流程、工程选型的全链路掌握。

知识点拆解:

  1. 池化思想:线程创建成本(内核态切换、栈内存、GC 压力);池化收益 = 复用 + 限流 + 隔离
  2. 7 大核心参数:corePoolSize / maximumPoolSize / keepAliveTime / unit / workQueue / threadFactory / handler
  3. 执行流程(三步判断):core → 队列未满 → max → 拒绝策略;队列优先级高于 max 扩容
  4. 4 种拒绝策略:AbortPolicy(默认抛异常)、DiscardPolicy(静默丢弃)、DiscardOldestPolicy(丢队列头)、CallerRunsPolicy(调用者执行,天然限流)
  5. 4 种队列:ArrayBlockingQueue(有界)、LinkedBlockingQueue(可无界 OOM 风险)、SynchronousQueue(不存储)、PriorityBlockingQueue(优先级)
  6. 5 态:RUNNING → SHUTDOWN → STOP → TIDYING → TERMINATED
  7. Executors 禁用:FixedThreadPool/SingleThreadExecutor 用无界队列 OOM;CachedThreadPool 无 max 线程暴涨;ScheduledThreadPool 无界队列
  8. 参数估算:CPU 密集 N_cpu×1;IO 密集 N_cpu×2 或 N_cpu×(1+wait/compute)
  9. 监控:JMX MBean 暴露 queueSize/activeCount/completedTaskCount/rejectedCount

第二部分:考察方向与延伸递进

考察方向:

延伸递进面试题:

  1. ThreadPoolExecutor.execute 的源码流程?
  1. 为什么队列满了才扩非核心线程?
  1. 线程暴涨如何排查?
  1. ForkJoinPool 和 ThreadPoolExecutor 区别?
  1. JDK 21 虚拟线程能替代线程池吗?
  1. 动态线程池如何落地?

第三部分:面试者参考回答(300-600 字口语化)

面试官您好,线程池本质是池化思想,核心目标是复用线程 + 限流 + 隔离。

参数方面有 7 个:corePoolSize 常驻线程数、maximumPoolSize 最大线程数、keepAliveTime 非核心线程空闲回收时间、unit 时间单位、workQueue 阻塞队列、threadFactory 线程工厂(一定要给线程命名,方便排查)、handler 拒绝策略。

执行流程是三步判断:任务进来先看当前线程数是否小于 core,是就建核心线程;否则看队列是否满,不满入队;否则看是否小于 max,是就建非核心线程;都不行触发拒绝策略。注意队列优先级高于 max 扩容,这是很多人讲错的地方。

拒绝策略 4 种内置:AbortPolicy 抛异常(默认)、DiscardPolicy 静默丢弃、DiscardOldestPolicy 丢队列头重试、CallerRunsPolicy 调用者自己执行——这个我比较常用,天然限流让上游感受慢。

队列选择我一般看场景:CPU 密集用 SynchronousQueue 或无队列,max 拉高;IO 密集用 ArrayBlockingQueue 有界队列控内存;任务有优先级用 PriorityBlockingQueue。

我们项目里禁用 Executors,因为它内部用无界队列或无上限线程,容易 OOM。参数估算用 N_cpu × 2(IO 密集)做初值,再压测调优。动态调优接了配置中心,运行时改 corePoolSize / maximumPoolSize,配 JMX 监控 activeCount、queueSize、rejectedCount 告警。

我们踩过的坑是线程暴涨:某个下游变慢,队列积压,线程飙到几千,最后 JVM OOM。定位靠 threadFactory 命名的线程名 + jstack 抓栈。之后改成有界队列 + CallerRunsPolicy,队列满后直接压回上游,问题就解决了。


面试记录 2026-10-17(第 2 次)

题目:什么是线程池,如何实现的?

难度:low

标签:java/threadpool, general/knowledge

评分:⭐⭐⭐⭐☆(4/5)

练习次数:2

我的回答

线程池是池化资源提高利用率的一个工具,核心功能就是将创建出来的线程进行复用,而不是每次创建新的线程; 线程池通过配置核心线程数,阻塞队列,最大线程数,拒绝策略,线程池工程,非核心线程保留时间和对应时间单位; 当主线程从线程池中申请新线程时,先判定核心线程是否都已经被占用,如果没占用完就用一个核心线程执行任务,如果已经占完没有空闲的核心线程,那么就判定阻塞队列是否已经满了,如果没有满,就把任务先放到阻塞队列中,如果阻塞队列已经满了,就判定当前线程池中的线程数量是否已经达到最大线程数,如果没有,则创建一个新的线程去执行,如果活跃的线程数量已经达到了最大线程数量,那么就要执行拒绝策略了; 默认的拒绝策略有,吞没,拒绝了没什么反馈,直接就不执行了; 抛出异常,反馈没有办法正常执行了; 开启额外新的线程去进行处理; 使用当前主线程进行处理; 还可以自定义拒绝策略,比如出现问题后,发送告警,或者发送mq消息等后续异步执行。具体使用什么需要根据业务形态去考虑,比如业务侧会做处理,对异常进行把控,那么就用抛出异常,业务侧自己考虑处理方案

点评

优点:相比首次(2026-09-20,3/5)明显进步——7 大核心参数基本说全(corePoolSize/maximumPoolSize/workQueue/handler/threadFactory/keepAliveTime/unit)、执行流程(core → 队列 → max → 拒绝)顺序完全正确、拒绝策略能结合业务举例。

不足:漏 threadFactory 的命名作用(排查必备)、WorkQueue 类型(有界/无界/SynchronousQueue)、Executors 禁用原因、监控指标。

补充:参数估算(CPU 密集 N_cpu×1、IO 密集 N_cpu×2);有界队列防 OOM;CallerRunsPolicy 天然限流。

ℹ️ 完整讲解见上方首次记录(2026-09-20)