线程池基础面试题
问题 1:什么是 Java 线程池?它的核心设计思想是什么?
Java 线程池(ThreadPoolExecutor)是 JUC(java.util.concurrent)包下的线程管理工具,本质是一组预先创建的线程集合 + 任务队列 + 管理策略。
核心设计思想:
- 避免频繁创建 / 销毁线程的性能开销(线程的创建需要占用系统资源、销毁需要回收资源);
- 统一管理线程的生命周期,控制并发线程数量,防止因创建过多线程导致 CPU / 内存耗尽;
- 实现任务的异步执行和复用线程。
注意: 在我们的实际开发过程中也是使用线程池的方式来进行管理,这样做的好处是对线程的有效调度,以及避免了过多的创建和销毁。
问题 2:线程池的核心作用有哪些?
1.降低资源消耗:复用已创建的线程,减少线程创建 / 销毁的系统开销;
2.提高响应速度:任务到达时无需等待线程创建,直接使用空闲线程执行;
3.便于线程管理:可控制最大并发数、设置线程存活时间、监控线程状态等;
4.增强可扩展性:支持任务拒绝策略、线程工厂自定义、任务执行前后钩子等扩展功能。
问题 3:Java 中创建线程池有哪两种核心方式?分别说明适用场景
方式 1:通过ThreadPoolExecutor直接创建(推荐,可精准控制参数);
方式 2:通过Executors工具类创建(简单,但易引发资源问题,阿里开发手册不推荐)。
代码示例1:ThreadPoolExecutor 直接创建(推荐)
package main.threadpool;
import java.util.concurrent.*;
public class ThreadPoolDemo {
public static void main(String[] args) {
// 1. 定义线程池核心参数
int corePoolSize = 4; // 核心线程数(常驻线程数)
int maximumPoolSize = 10; // 最大线程数
long keepAliveTime = 10; // 非核心线程空闲存活时间
TimeUnit unit = TimeUnit.SECONDS; // 存活时间单位
BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(5); // 任务队列(容量3)
ThreadFactory threadFactory = Executors.defaultThreadFactory(); // 线程工厂(创建线程)
RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy(); // 拒绝策略
// 2. 创建线程池
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(
corePoolSize,
maximumPoolSize,
keepAliveTime,
unit,
workQueue,
threadFactory,
handler
);
// 3. 提交任务
for (int i = 1; i <= 10; i++) {
int taskNum = i;
threadPool.execute(() -> {
System.out.println("线程" + Thread.currentThread().getName() + "执行任务" + taskNum);
try {
Thread.sleep(1000); // 模拟任务执行耗时
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
// 4. 关闭线程池(用完必须关闭,否则进程不会结束)
threadPool.shutdown();
}
}
参数说明:
- corePoolSize:核心线程数,即使空闲也不会销毁(除非设置allowCoreThreadTimeOut(true));
- maximumPoolSize:线程池能创建的最大线程数;
- keepAliveTime:非核心线程空闲超过该时间会被销毁;
- workQueue:任务队列,核心线程满时,新任务会放入队列;
- threadFactory:自定义线程创建方式(如设置线程名、优先级);
handler:拒绝策略(队列满 + 最大线程数满时,处理新任务的方式)。
package main.threadpool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
public class ExecutorsDemo {
public static void main(String[] args) {
// 1. 创建常见的线程池(Executors提供的快捷方式)
// 方式1:固定线程数线程池
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
// 方式2:单线程线程池
ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();
// 方式3:缓存线程池(按需创建,空闲60s销毁)
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
// 方式4:定时任务线程池
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(2);
// 2. 使用固定线程池执行任务
for (int i = 1; i <= 5; i++) {
int taskNum = i;
fixedThreadPool.execute(() -> {
System.out.println("线程" + Thread.currentThread().getName() + "执行任务" + taskNum);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
// 3. 关闭线程池
fixedThreadPool.shutdown();
}
}
Executors 的问题
- newFixedThreadPool/newSingleThreadExecutor:队列使用LinkedBlockingQueue(无界队列),任务过多会导致 OOM;
- newCachedThreadPool:最大线程数为Integer.MAX_VALUE,可能创建大量线程导致 OOM;
- 因此阿里开发手册要求:禁止使用 Executors 创建线程池,必须手动通过 ThreadPoolExecutor 创建。
问题 3:线程池的执行流程是什么?
1.任务提交时,先判断核心线程池是否已满:未满则创建核心线程执行任务;
2.核心线程池已满,判断任务队列是否已满:未满则将任务放入队列;
3.任务队列已满,判断线程池是否达到最大线程数:未达到则创建非核心线程执行任务;
4.达到最大线程数,则触发拒绝策略处理任务。
问题 4:线程池的 4 种拒绝策略分别是什么
1.AbortPolicy(默认):直接抛出RejectedExecutionException异常,终止任务;
2.CallerRunsPolicy:由提交任务的线程(如 main 线程)自己执行任务;
3.DiscardPolicy:直接丢弃新任务,无任何提示;
4.DiscardOldestPolicy:丢弃队列中最旧的任务,将新任务加入队列。

浙公网安备 33010602011771号