线程池的核心参数和执行流程?

2025年 阅读约 12 分钟 面试指南 · Java面试 · Java并发

深入解析Java线程池ThreadPoolExecutor:7大核心参数详解、完整执行流程(核心线程→阻塞队列→最大线程→拒绝策略)、4种拒绝策略对比、常见线程池类型(Fixed/Cached/Single/Scheduled)、线程数合理配置公式,附完整源码分析和面试模拟。

一句话总结

ThreadPoolExecutor 有 7 个核心参数:corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue、threadFactory、handler。执行流程:新任务来 → 核心线程未满则创建核心线程 → 核心线程满则放入队列 → 队列满则创建临时线程(最多到 maximumPoolSize)→ 线程数达到 maximumPoolSize 且队列满则执行拒绝策略。临时线程空闲超过 keepAliveTime 会被回收。

初级理解

为什么需要线程池?

线程的创建和销毁开销大(涉及系统调用、内存分配)。线程池通过复用线程来:减少创建销毁开销、控制并发数量、统一管理线程。

7 大核心参数

public ThreadPoolExecutor( int corePoolSize, // ① 核心线程数(常驻线程) int maximumPoolSize, // ② 最大线程数 long keepAliveTime, // ③ 空闲线程存活时间 TimeUnit unit, // ④ 时间单位 BlockingQueue<Runnable> workQueue, // ⑤ 阻塞队列 ThreadFactory threadFactory, // ⑥ 线程工厂 RejectedExecutionHandler handler // ⑦ 拒绝策略 )
参数说明
corePoolSize核心线程数,即使空闲也不会被回收(除非 allowCoreThreadTimeOut=true)
maximumPoolSize最大线程数 = 核心线程 + 临时线程
keepAliveTime临时线程空闲超过此时间被回收
workQueue任务队列,核心线程满时新任务放入队列
threadFactory创建线程的工厂,可自定义线程名、优先级等
handler拒绝策略,线程和队列都满时如何处理新任务
一句话总结:线程池 = 核心线程 + 临时线程 + 任务队列 + 拒绝策略,通过复用线程提高性能。

中级深入

完整执行流程

// ThreadPoolExecutor.execute() 简化源码 public void execute(Runnable command) { int c = ctl.get(); // ctl 高3位=状态,低29位=线程数 // 步骤1:当前线程数 < corePoolSize → 创建核心线程 if (workerCountOf(c) < corePoolSize) { if (addWorker(command, true)) // true=核心线程 return; c = ctl.get(); } // 步骤2:核心线程满 → 尝试放入队列 if (isRunning(c) && workQueue.offer(command)) { int recheck = ctl.get(); // 双重检查:如果线程池已关闭,从队列移除并拒绝 if (!isRunning(recheck) && remove(command)) reject(command); // 如果线程数为0(可能核心线程被回收),补充一个线程 else if (workerCountOf(recheck) == 0) addWorker(null, false); } // 步骤3:队列满 → 创建临时线程(最多到 maximumPoolSize) else if (!addWorker(command, false)) // false=非核心线程 // 步骤4:达到 maximumPoolSize → 执行拒绝策略 reject(command); }

4 种拒绝策略

策略行为适用场景
AbortPolicy(默认)抛 RejectedExecutionException必须感知任务被拒绝
CallerRunsPolicy由调用者线程执行任务可承受延迟,不能丢任务
DiscardPolicy直接丢弃,不抛异常允许丢任务(如日志)
DiscardOldestPolicy丢弃队列中最旧的任务,重试优先处理最新任务

常见阻塞队列

队列特点适用
SynchronousQueue不存储任务,直接交给线程CachedThreadPool
LinkedBlockingQueue无界(默认 Integer.MAX_VALUE)FixedThreadPool
ArrayBlockingQueue有界,需指定容量推荐生产使用
PriorityBlockingQueue按优先级排序需要优先级调度
中级要点:执行流程四步走:核心线程 → 队列 → 最大线程 → 拒绝。队列选型很重要,LinkedBlockingQueue 无界可能导致 OOM。

高级拓展

常见线程池类型及风险

// Executors 提供的工厂方法(阿里规范禁止使用!) // FixedThreadPool — 固定线程数,无界队列 → 可能 OOM Executors.newFixedThreadPool(10); // 等价于:new ThreadPoolExecutor(10, 10, 0L, TimeUnit.MILLISECONDS, // new LinkedBlockingQueue<Runnable>()); // CachedThreadPool — 可缓存,线程数无上限 → 可能创建大量线程 Executors.newCachedThreadPool(); // 等价于:new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, // new SynchronousQueue<Runnable>()); // SingleThreadExecutor — 单线程,无界队列 → 可能 OOM Executors.newSingleThreadExecutor(); // 等价于:new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, // new LinkedBlockingQueue<Runnable>()); // ScheduledThreadPool — 定时任务 Executors.newScheduledThreadPool(5);

线程数如何合理配置?

任务类型公式说明
CPU 密集型CPU 核数 + 1减少上下文切换
IO 密集型CPU 核数 × 2IO 等待时可切换其他线程
混合型CPU 核数 × 期望利用率 × (1 + WT/ST)WT=等待时间,ST=计算时间

线程池状态转换

状态说明转换
RUNNING接受新任务,处理队列中任务初始状态
SHUTDOWN不接受新任务,处理队列中剩余任务shutdown()
STOP不接受新任务,不处理队列中任务,中断正在执行的任务shutdownNow()
TIDYING所有任务终止,workerCount=0过渡状态
TERMINATED线程池彻底终止terminated() 回调后
高级加分项:能说出 Executors 工厂方法的 OOM 风险,能根据任务类型给出线程数配置公式,能解释 shutdown/shutdownNow 的区别,知道 ctl 的高 3 位存状态、低 29 位存线程数的设计。

实战场景

场景一:生产环境线程池配置

// 推荐:手动创建,使用有界队列 ThreadPoolExecutor executor = new ThreadPoolExecutor( 5, // 核心线程 10, // 最大线程 60L, TimeUnit.SECONDS, // 空闲超时 new ArrayBlockingQueue<>(100), // 有界队列 new ThreadFactoryBuilder().setNameFormat("biz-%d").build(), new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略 );

场景二:线程池监控

// 通过 ScheduledExecutorService 定期监控 ScheduledExecutorService monitor = Executors.newSingleThreadScheduledExecutor(); monitor.scheduleAtFixedRate(() -> { System.out.println("活跃线程: " + executor.getActiveCount()); System.out.println("队列大小: " + executor.getQueue().size()); System.out.println("完成任务: " + executor.getCompletedTaskCount()); System.out.println("线程池大小: " + executor.getPoolSize()); }, 0, 5, TimeUnit.SECONDS);

常见坑

原因解决方案
用 Executors 创建无界队列或无限线程 → OOM手动 new ThreadPoolExecutor
线程池中 ThreadLocal 不清理线程复用导致值残留任务完成后 remove()
shutdown 后不 awaitTermination任务未执行完就退出shutdown + awaitTermination

面试模拟

Q:线程池的核心参数和执行流程?

A:7 个参数:corePoolSize、maximumPoolSize、keepAliveTime、unit、workQueue、threadFactory、handler。执行流程:核心线程未满创建核心线程 → 核心线程满放入队列 → 队列满创建临时线程(最多到 maximumPoolSize)→ 达到最大线程且队列满执行拒绝策略。临时线程空闲超时回收。

Q:为什么阿里禁止用 Executors 创建线程池?

A:FixedThreadPool 和 SingleThreadPool 使用无界 LinkedBlockingQueue,任务堆积会导致 OOM。CachedThreadPool 允许创建无限线程(Integer.MAX_VALUE),也会 OOM。应该手动 new ThreadPoolExecutor 并使用有界队列。

Q:shutdown() 和 shutdownNow() 的区别?

A:shutdown() 将线程池状态设为 SHUTDOWN,不再接受新任务,但会继续处理队列中已有的任务。shutdownNow() 将状态设为 STOP,不再接受新任务,中断正在执行的任务,返回队列中未执行的任务列表。两者都不会等待任务完成,需要配合 awaitTermination()。