Java 线程池详解
从原理到实战,全面掌握线程池核心技能
一、线程池核心原理
提交任务
线程池
任务队列
workQueue
核心线程1
核心线程2
核心线程N
临时线程1
临时线程2
任务
线程池 = 任务队列 + 工作线程
| 组件 | 作用 |
|---|---|
| 任务队列 | 缓存待执行任务 |
| 工作线程 | 从队列取任务执行 |
| 线程管理 | 控制线程数量、回收空闲线程 |
二、线程池处理流程
是
否
否
是
是
否
提交任务
线程数 < corePoolSize?
创建新线程
队列已满?
执行任务
加入队列等待
线程数 < maximumPoolSize?
创建临时线程
触发拒绝策略
拒绝任务
执行流程:
- 线程数 < corePoolSize → 创建新线程执行
- 线程数 >= corePoolSize → 任务加入队列
- 队列满 + 线程数 < maximumPoolSize → 创建临时线程
- 队列满 + 线程数 = maximumPoolSize → 拒绝任务
三、线程池 7 大参数
newThreadPoolExecutor(int corePoolSize,// 1. 核心线程数int maximumPoolSize,// 2. 最大线程数long keepAliveTime,// 3. 空闲线程存活时间TimeUnit unit,// 4. 时间单位BlockingQueue<Runnable> workQueue,// 5. 任务队列ThreadFactory threadFactory,// 6. 线程工厂RejectedExecutionHandler handler // 7. 拒绝策略);
| 参数 | 说明 | 示例值 |
|---|---|---|
| corePoolSize | 核心线程数,常驻线程数 | 10 |
| maximumPoolSize | 最大线程数,弹性扩展上限 | 50 |
| keepAliveTime | 空闲线程存活时间 | 60 |
| unit | 时间单位 | TimeUnit.SECONDS |
| workQueue | 任务队列 | new ArrayBlockingQueue<>(100) |
| threadFactory | 线程创建工厂 | Executors.defaultThreadFactory() |
| handler | 拒绝策略 | new ThreadPoolExecutor.AbortPolicy() |
四、任务队列选择
| 队列类型 | 特点 | 适用场景 |
|---|---|---|
| ArrayBlockingQueue | 有界队列,需指定容量 | 限流场景 |
| LinkedBlockingQueue | 无界队列,默认 Integer.MAX_VALUE | 任务堆积风险 |
| SynchronousQueue | 无容量,直接交付 | 快速响应场景 |
| DelayedWorkQueue | 延迟队列 | 定时任务 |
// 有界队列(推荐)newArrayBlockingQueue<>(100)// 无界队列(谨慎使用)newLinkedBlockingQueue<>()// 同步队列(适合耗时短的任务)newSynchronousQueue<>()五、拒绝策略
| 策略 | 行为 | 适用场景 |
|---|---|---|
| AbortPolicy | 抛异常 | 默认,需业务处理 |
| CallerRunsPolicy | 调用者线程执行 | 缓冲压力,慎用 |
| DiscardPolicy | 静默丢弃 | 日志等非核心任务 |
| DiscardOldestPolicy | 丢弃最老任务 | 优先处理新任务 |
// 默认:抛异常newAbortPolicy()// 调用者执行newCallerRunsPolicy()// 丢弃任务newDiscardPolicy()// 丢弃最老任务newDiscardOldestPolicy()六、线程工厂
ThreadFactory factory =newThreadFactory(){privateAtomicInteger count =newAtomicInteger(1);@OverridepublicThreadnewThread(Runnable r){Thread thread =newThread(r); thread.setName("MyThread-"+ count.getAndIncrement()); thread.setDaemon(false);// 非守护线程return thread;}};常用配置:
- 线程命名
- 守护线程设置
- 线程优先级
七、Executors 工具类
| 方法 | 说明 | 风险 |
|---|---|---|
newFixedThreadPool(n) | 固定 n 线程 | 无界队列,OOM |
newSingleThreadExecutor() | 单线程 | 无界队列,OOM |
newCachedThreadPool() | 弹性扩展 | 最大 Integer.MAX_VALUE |
newScheduledThreadPool(n) | 定时任务 | 无界队列,OOM |
阿里巴巴规范:不推荐使用!
// 不推荐:可能 OOMExecutorService pool =Executors.newFixedThreadPool(10);// 推荐:手动配置ExecutorService pool =newThreadPoolExecutor(10,50,60L,TimeUnit.SECONDS,newArrayBlockingQueue<>(100),newThreadPoolExecutor.AbortPolicy());八、线程池状态
创建
shutdown()
shutdownNow()
队列空 + 无活跃线程
无活跃线程
terminated()执行完毕
RUNNING
SHUTDOWN
STOP
TIDYING
TERMINATED
| 状态 | 值 | 说明 |
|---|---|---|
| RUNNING | 111 | 接收新任务,执行任务 |
| SHUTDOWN | 000 | 不接收新任务,执行已提交任务 |
| STOP | 001 | 不接收新任务,不执行已提交任务 |
| TIDYING | 010 | 任务执行完毕,准备终止 |
| TERMINATED | 011 | 完全终止 |
九、实战配置
1. CPU 密集型任务
// CPU 核心数 + 1int cpuCores =Runtime.getRuntime().availableProcessors();newThreadPoolExecutor( cpuCores +1, cpuCores +1,0L,TimeUnit.MILLISECONDS,newLinkedBlockingQueue<>(1000));2. IO 密集型任务
// CPU 核心数 * 2int cpuCores =Runtime.getRuntime().availableProcessors();newThreadPoolExecutor( cpuCores *2, cpuCores *2,60L,TimeUnit.SECONDS,newLinkedBlockingQueue<>(1000));3. 混合型任务
newThreadPoolExecutor( cpuCores +1, cpuCores *2,60L,TimeUnit.SECONDS,newArrayBlockingQueue<>(500));十、线程池监控
1. 常用监控方法
ThreadPoolExecutor executor =newThreadPoolExecutor(...);// 活跃线程数 executor.getActiveCount();// 队列任务数 executor.getQueue().size();// 已完成任务数 executor.getCompletedTaskCount();// 总任务数 executor.getTaskCount();// 线程池是否Terminated executor.isTerminated();2. 线程池监控示例
publicclassThreadPoolMonitor{publicstaticvoidprintStatus(ThreadPoolExecutor executor){System.out.println("====================");System.out.println("线程池大小: "+ executor.getPoolSize());System.out.println("活跃线程数: "+ executor.getActiveCount());System.out.println("队列任务数: "+ executor.getQueue().size());System.out.println("已完成任务: "+ executor.getCompletedTaskCount());System.out.println("总任务数: "+ executor.getTaskCount());System.out.println("====================");}}十一、优雅关闭线程池
ThreadPoolExecutor executor =newThreadPoolExecutor(...);// 1. 拒绝新任务 executor.shutdown();// 2. 等待任务完成(带超时)if(!executor.awaitTermination(60,TimeUnit.SECONDS)){// 3. 强制中断 executor.shutdownNow();}// 或者直接暴力关闭 executor.shutdownNow();关闭原则:
- 先
shutdown()拒绝新任务 - 等待任务完成或超时
- 超时后
shutdownNow()强制中断
十二、常见问题
1. 线程池参数设置多大?
| 任务类型 | 推荐线程数 |
|---|---|
| CPU 密集型 | CPU 核心数 + 1 |
| IO 密集型 | CPU 核心数 * 2 |
| 混合型 | CPU 核心数 + 1 ~ CPU 核心数 * 2 |
2. 队列容量设置多大?
// 经验公式 队列容量 = 核心线程数 * 期望响应时间(秒)*23. 线程池会 OOM 吗?
会!常见原因:
- LinkedBlockingQueue 无界队列堆积
- 任务过多且执行慢
- 拒绝策略不合理
解决:
- 使用有界队列
- 合理设置 maximumPoolSize
- 监控队列大小
4. 核心线程会被回收吗?
默认不会!设置允许回收:
executor.allowCoreThreadTimeOut(true);十三、总结
线程池核心
参数配置
core/max/queue
队列选择
Array/Linked/Synchronous
拒绝策略
4种策略
监控与调优
合理配置
避免 OOM
优雅关闭
防止任务丢失
核心要点:
| 要点 | 说明 |
|---|---|
| 参数配置 | 根据任务类型选择 core/max/queue |
| 队列选择 | 优先使用有界队列 |
| 拒绝策略 | 根据业务选择合适的策略 |
| 监控 | 定期监控队列大小、活跃线程数 |
| 关闭 | 先 shutdown 再 awaitTermination |