字节面试题-JAVA多线程
面试题
题目
Java ThreadPoolExecutor,核心线程corePoolSize = 1,最大线程maximumPoolSize = 2,阻塞队列容量=2,拒绝策略使用默认AbortPolicy(丢弃任务抛出异常)。依次提交任务1、2、3、4、5,请描述任务执行过程、启动顺序、结束顺序。
线程池执行原则:
- 运行线程数<核心线程数:新建核心线程执行任务;
- 核心线程已满,任务放进队列,队列未满优先入队;
- 队列满了,线程数<最大线程数,则创建非核心线程执行任务;
- 队列已满且线程数达到最大线程数,触发拒绝策略。
分步执行过程
- 提交任务1:当前工作线程为0<1,创建核心线程Thread‑A执行任务1。
运行线程:Thread‑A;队列:空。 - 提交任务2:核心线程已经占满,队列还有空位,任务2放入队列;队列:[2]。
- 提交任务3:队列还剩余1个位置,任务3入队,队列已满;队列:[2,3]。
- 提交任务4:队列已满,此时运行线程数1<2,创建非核心线程Thread‑B执行任务4。
运行线程:Thread‑A执行任务1,Thread‑B执行任务4。队列:[2,3]。 - 提交任务5:队列已满,工作线程已经达到最大值2,触发AbortPolicy拒绝策略,任务5直接被丢弃,抛出RejectedExecutionException,永远不会执行。
1.任务开始执行顺序(启动时刻固定)
- 最先开始运行:任务1(Thread‑A)、任务4(Thread‑B),两个任务并行启动;
- 任务2、3此时仅存放在队列里,不会开始执行;
- 任务5直接拒绝。
2.任务结束顺序(分两种场景,面试重点)
场景1:面试考题默认条件:每个任务执行耗时完全相同(标准答案)
- Thread‑A执行完任务1、Thread‑B执行完任务4之后两个线程空闲;
- Thread‑A、Thread‑B争抢队列里面任务2和3:线程A执行任务2,线程B执行任务3;
任务完成顺序:1、4执行完毕之后,2、3并行执行;整体完成顺序:1‑4‑2‑3。
场景2:真实生产环境,由操作系统调度决定
- 如果Thread‑A先执行完任务1,Thread‑B还在执行任务4:只有Thread‑A空闲,任务2、3全部由Thread‑A串行执行,完成顺序:1‑4‑2‑3。
- 如果Thread‑B先执行完任务4,Thread‑A还在执行任务1:Thread‑B空闲取出任务2;之后Thread‑A执行完毕再取出任务3,完成顺序:4‑2‑1‑3。
关键点:队列中的任务2、3,空闲线程都可以竞争获取,并不是只能由核心线程Thread‑A执行。
3.线程B销毁时机(追加考点)
- 队列里面还有任务2、3:线程B领取队列任务继续运行,不会空闲,不会销毁;
- 当队列所有任务执行完毕队列为空后,线程B(非核心线程)空闲持续keepAliveTime默认60秒,没有新任务进来,线程B销毁;Thread‑A为核心线程会一直保留。
精简面试口述版(背这段)
- 任务1创建核心线程执行;任务2、3进入队列;队列满后创建非核心线程执行任务4;任务5触发拒绝策略被丢弃。
- 任务1和任务4并行开始执行;队列中的任务2和3由空闲线程竞争执行。
- 做题默认每个任务耗时一致:完成顺序为1,4,2,3;真实环境1和4结束先后由操作系统调度决定;任务全部执行完毕后,线程B空闲60秒销毁,核心线程保留。
易错点总结(面试坑)
- 队列满了之后才会创建非核心线程,队列有空闲时不会创建第二个线程;
- 非核心线程空闲之后同样会消费队列任务,不是只能核心线程消费队列任务;
- 只有线程超过核心线程数的部分线程,受keepAliveTime空闲回收控制。

浙公网安备 33010602011771号