字节面试题-JAVA多线程

面试题

题目

Java ThreadPoolExecutor,核心线程corePoolSize = 1,最大线程maximumPoolSize = 2,阻塞队列容量=2,拒绝策略使用默认AbortPolicy(丢弃任务抛出异常)。依次提交任务1、2、3、4、5,请描述任务执行过程、启动顺序、结束顺序。
线程池执行原则:

  1. 运行线程数<核心线程数:新建核心线程执行任务;
  2. 核心线程已满,任务放进队列,队列未满优先入队;
  3. 队列满了,线程数<最大线程数,则创建非核心线程执行任务;
  4. 队列已满且线程数达到最大线程数,触发拒绝策略。

分步执行过程

  1. 提交任务1:当前工作线程为0<1,创建核心线程Thread‑A执行任务1。
    运行线程:Thread‑A;队列:空。
  2. 提交任务2:核心线程已经占满,队列还有空位,任务2放入队列;队列:[2]。
  3. 提交任务3:队列还剩余1个位置,任务3入队,队列已满;队列:[2,3]。
  4. 提交任务4:队列已满,此时运行线程数1<2,创建非核心线程Thread‑B执行任务4。
    运行线程:Thread‑A执行任务1,Thread‑B执行任务4。队列:[2,3]。
  5. 提交任务5:队列已满,工作线程已经达到最大值2,触发AbortPolicy拒绝策略,任务5直接被丢弃,抛出RejectedExecutionException,永远不会执行。

1.任务开始执行顺序(启动时刻固定)

  • 最先开始运行:任务1(Thread‑A)、任务4(Thread‑B),两个任务并行启动;
  • 任务2、3此时仅存放在队列里,不会开始执行;
  • 任务5直接拒绝。

2.任务结束顺序(分两种场景,面试重点)

场景1:面试考题默认条件:每个任务执行耗时完全相同(标准答案)

  1. Thread‑A执行完任务1、Thread‑B执行完任务4之后两个线程空闲;
  2. Thread‑A、Thread‑B争抢队列里面任务2和3:线程A执行任务2,线程B执行任务3;
    任务完成顺序:1、4执行完毕之后,2、3并行执行;整体完成顺序:1‑4‑2‑3。

场景2:真实生产环境,由操作系统调度决定

  1. 如果Thread‑A先执行完任务1,Thread‑B还在执行任务4:只有Thread‑A空闲,任务2、3全部由Thread‑A串行执行,完成顺序:1‑4‑2‑3。
  2. 如果Thread‑B先执行完任务4,Thread‑A还在执行任务1:Thread‑B空闲取出任务2;之后Thread‑A执行完毕再取出任务3,完成顺序:4‑2‑1‑3。

关键点:队列中的任务2、3,空闲线程都可以竞争获取,并不是只能由核心线程Thread‑A执行。

3.线程B销毁时机(追加考点)

  1. 队列里面还有任务2、3:线程B领取队列任务继续运行,不会空闲,不会销毁;
  2. 当队列所有任务执行完毕队列为空后,线程B(非核心线程)空闲持续keepAliveTime默认60秒,没有新任务进来,线程B销毁;Thread‑A为核心线程会一直保留。

精简面试口述版(背这段)

  1. 任务1创建核心线程执行;任务2、3进入队列;队列满后创建非核心线程执行任务4;任务5触发拒绝策略被丢弃。
  2. 任务1和任务4并行开始执行;队列中的任务2和3由空闲线程竞争执行。
  3. 做题默认每个任务耗时一致:完成顺序为1,4,2,3;真实环境1和4结束先后由操作系统调度决定;任务全部执行完毕后,线程B空闲60秒销毁,核心线程保留。

易错点总结(面试坑)

  1. 队列满了之后才会创建非核心线程,队列有空闲时不会创建第二个线程;
  2. 非核心线程空闲之后同样会消费队列任务,不是只能核心线程消费队列任务;
  3. 只有线程超过核心线程数的部分线程,受keepAliveTime空闲回收控制。
posted @ 2026-07-09 17:21  不该懂的还是懂了  阅读(14)  评论(0)    收藏  举报