Files
autumn-recruitment/01.Java/concurrent/线程池参数与拒绝策略_test.md
T

8.3 KiB
Raw Blame History

tags, create time
tags create time
test/review
java
thread-pool
ThreadPoolExecutor
rejection-policy
task-queue
2026-08-09 12:00

线程池参数与拒绝策略_测试题

概述

本测试覆盖 ThreadPoolExecutor 七大参数、任务提交流程、四种拒绝策略、工作队列类型以及 CPU/IO 密集型调优公式,共 10 道题目(6 道选择题 + 3 道填空题 + 1 道简答题)。


一、选择题(6道,由浅入深)

难度阶梯: Q1-Q2 基础概念 → Q3-Q4 核心原理 → Q5-Q6 深入应用/边界场景

Q1(基础)— 考察定义层面

ThreadPoolExecutor 构造方法的七个参数中,前五个决定了线程池的什么?

A. 线程的安全性和死锁检测
B. 容量模型和任务调度逻辑
C. 线程的名称格式和优先级
D. 拒绝策略的具体行为

Q2(基础)— 考察行为判断

调用 Executors.newFixedThreadPool(10) 时,底层实际使用的是哪种队列?

A. ArrayBlockingQueue(有界)
B. LinkedBlockingQueue(无界,capacity = Integer.MAX_VALUE)
C. SynchronousQueue
D. PriorityBlockingQueue

Q3(进阶)— 考察核心原理

当一个线程池配置了 corePoolSize=8、maximumPoolSize=16、workQueue 容量为 100 时,假设当前已有 8 个核心线程在运行,此时同时提交 150 个新任务。请问有多少任务会被放入队列、多少会触发非核心线程创建、多少会触发拒绝策略?

A. 100 入队 + 0 创建非核心 + 50 触发拒绝
B. 100 入队 + 8 创建非核心 + 42 触发拒绝
C. 100 入队 + 16 创建非核心 + 34 触发拒绝
D. 150 全部入队,不会触发非核心线程

Q4(进阶)— 考察比较与辨析

关于四种拒绝策略,以下描述正确的是:

A. AbortPolicy 是默认策略,会静默丢弃任务而不抛出异常
B. CallerRunsPolicy 会将任务回退到提交任务的线程执行,起到降速缓冲的作用
C. DiscardOldestPolicy 是最安全的策略,永远不会丢失任何任务
D. DiscardPolicy 适合处理可以丢失的非关键任务,会抛出异常通知调用方

Q5(深入)— 考察场景推理

某服务在流量突增时出现了 OOM 错误,经排查发现使用的是 Executors.newCachedThreadPool()。最可能的原因是:

A. CachedThreadPool 的工作队列是有界的,流量大会导致拒绝策略触发
B. CachedThreadPool 的核心线程数为 0,所有任务都必须创建新线程,无限增长导致 OOM
C. CachedThreadPool 的 keepAliveTime 太短,频繁创建销毁线程带来额外开销
D. CachedThreadPool 使用 ArrayBlockingQueue 且有容量上限

Q6(深入)— 考察数值计算

在一台 8 核机器上运行 IO 密集型任务(阻塞系数取 0.85),根据经验公式,推荐的线程数约为:

A. 9 个(N + 1)
B. 16 个(2 × N)
C. 53 个(N / (1 - 0.85))
D. 128 个(N × 16)


二、填空题(3道)

F1 — 填空1

线程池任务提交的流转逻辑遵循以下优先级:第一步创建核心线程;第二步如果已达核心线程数且队列未满则__(1);第三步如果队列已满但线程数未达到 maximumPoolSize 则创建(2);第四步如果线程数达到上限且队列仍满则触发(3)__。

提示: 回忆流程图中的四个分支路径,注意每一步的前置条件。

F2 — 填空2

在 8 核机器上处理 CPU 密集型任务,推荐的线程数公式是 (1)(其中 N 为 CPU 核心数),多出来的那一个线程是为了容忍页缺失等偶发停顿。而对于 IO 密集型任务(阻塞系数 0.85),公式则是 (2)。

提示: CPU 密集型和 IO 密型的公式完全不同,前者简单后者需要引入阻塞系数。

F3 — 填空3

ArrayBlockingQueue 属于__(1)类型的阻塞队列,特点是 FIFO 且可控,(2)__在生产中使用。与之相对,LinkedBlockingQueue 的默认 capacity 为 (3),容易导致任务堆积甚至 OOM。

提示: 关注各队列类型的"有界/无界"属性和生产推荐度。


三、简答题(1道)

S1

某微服务使用了如下线程池配置进行异步任务处理:

ExecutorService pool = Executors.newFixedThreadPool(20);
for (Request req : batchRequests) {
    pool.submit(() -> process(req));  // 每个请求耗时约 200ms
}

大促期间突然出现以下现象:

  • 服务响应变慢,RT 飙升
  • 监控显示 JVM 堆内存持续上升并最终 OOM
  • CPU 使用率正常,说明不是计算瓶颈

请分析:

  1. 这段代码存在什么根本性问题?为什么会触发 OOM?
  2. 如果要改造这段代码,至少需要改进哪三个方面?(结合线程池配置原则)
  3. 如果决定将拒绝策略改为 CallerRunsPolicy,需要注意什么风险?

答题框架提示:

  • 第 1 问抓住 Executors.newFixedThreadPool 的底层队列特性
  • 第 2 问从"有界队列 + 自定义核心线程数 + 手动构造"入手
  • 第 3 问从 CallerRunsPolicy 的行为特征推导其对业务链路的影响

参考答案与解析

选择题答案

题号 正确答案 解析
Q1 B 前五个参数(corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue)共同定义了线程池的容量模型和任务调度逻辑。threadFactory 和 handler 是扩展点。
Q2 B newFixedThreadPool 内部使用 LinkedBlockingQueue,其默认 capacity 为 Integer.MAX_VALUE(无界),这会导致任务不断堆积而不会触发非核心线程创建或拒绝策略。
Q3 B 核心线程 8 个已满,150 个任务先到队列排,队列容量 100 入队 100 个;剩余 50 个触发第三步创建非核心线程,最多可创建 16-8=8 个非核心线程处理 8 个任务;最后 50-8=42 个触发拒绝策略。
Q4 B B 正确:CallerRunsPolicy 由提交线程执行,起到降速缓冲作用。A 错(AbortPolicy 抛出异常),C 错(DiscardOldestPolicy 会丢弃老任务),D 错(DiscardPolicy 静默丢弃不抛异常)。
Q5 B CachedThreadPool 的 corePoolSize=0,所有任务都需新建线程处理,且 keepAliveTime=60s。无界队列 + 无限创建线程,在高并发下线程数暴增导致 OOM。
Q6 C IO 密集型公式:N / (1 - 阻塞系数) = 8 / (1 - 0.85) = 8 / 0.15 ≈ 53 个线程。CPU 密集型的 N+1=9 不适用于 IO 场景。

填空题答案

题号 答案 解析
F1 (1)放入队列排队 (2)非核心线程 (3)拒绝策略 任务提交的四级决策路径:核心线程→队列→非核心线程→拒绝策略。缺一不可。
F2 (1)N + 1 (2)N / (1 - 阻塞系数) CPU 密集型几乎一直在计算,不需要等待 IO,多余线程只会增加上下文切换开销;IO 密集型线程大量时间在等待 IO,可以多开线程提高利用率。
F3 (1)有界 (2)推荐 (3)Integer.MAX_VALUE ArrayBlockingQueue 明确指定容量上限,安全可控;LinkedBlockingQueue 默认无界是大坑。

简答题参考答案

S1:参考答案要点:

  1. 根本问题:Executors.newFixedThreadPool(20) 底层使用无界队列 LinkedBlockingQueue(capacity = MAX_VALUE),150 个任务全部入队排队,永远不会创建超过 20 个线程。但由于 process(req) 耗时 200ms,队列中堆积的任务引用不会被释放,加上请求对象本身的内存占用,堆持续增长最终 OOM。本质上是一个典型的"无界队列导致的任务堆积 OOM"。
  2. ① 换为有界队列的 ThreadPoolExecutor(如 ArrayBlockingQueue(100));② 根据 IO 密集型公式重新计算核心线程数和最大线程数;③ 显式配置拒绝策略(如 CallerRunsPolicy)而非依赖默认的 AbortPolicy 抛异常打断链路。
  3. CallerRunsPolicy 会将任务回退到提交线程执行——在这个场景下,如果提交线程是 HTTP 请求线程,那么处理本身就需要 200ms 的任务会在请求线程里同步执行,直接拖慢整个业务链路,导致更多的请求涌入时雪崩效应加剧。使用时务必确认调用方的线程性质。

评分标准:答出任意 2 个要点即可得满分;完全正确需覆盖全部要点。

关联笔记