线程池原理
核心参数(7大参数)
ThreadPoolExecutor 是线程池的核心实现类,其构造函数包含 7 个关键参数:
1 2 3 4 5 6 7 8 9
| public ThreadPoolExecutor( int corePoolSize, // 核心线程数 int maximumPoolSize, // 最大线程数 long keepAliveTime, // 空闲线程存活时间 TimeUnit unit, // 时间单位 BlockingQueue<Runnable> workQueue, // 任务队列 ThreadFactory threadFactory, // 线程工厂 RejectedExecutionHandler handler // 拒绝策略 )
|
参数详解
| 参数 |
说明 |
建议 |
| corePoolSize |
核心线程数,即使空闲也不会被回收 |
CPU密集型:N+1,IO密集型:2N 👉详解 |
| maximumPoolSize |
线程池最大线程数 |
根据业务峰值设置 |
| keepAliveTime |
非核心线程空闲存活时间 |
一般 60s |
| unit |
keepAliveTime 的时间单位 |
TimeUnit.SECONDS |
| workQueue |
任务等待队列 |
有界队列更安全 |
| threadFactory |
创建线程的工厂,可自定义线程名 |
建议自定义便于排查 |
| handler |
队列满且线程数达到最大时的拒绝策略 |
根据业务选择 |
工作流程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| ┌─────────────────┐ │ 提交任务 │ └────────┬────────┘ │ ▼ ┌──────────────────────────────┐ │ 核心线程数 < corePoolSize? │ └──────────────┬───────────────┘ YES │ │ NO ▼ ▼ ┌─────────────┐ ┌─────────────────┐ │ 创建核心线程 │ │ 任务队列未满? │ │ 执行任务 │ └────────┬────────┘ └─────────────┘ YES │ │ NO ▼ ▼ ┌─────────┐ ┌──────────────────┐ │ 入队等待 │ │ 线程数 < maxSize? │ └─────────┘ └────────┬─────────┘ YES │ │ NO ▼ ▼ ┌─────────┐ ┌─────────┐ │创建非核心│ │ 拒绝策略 │ │线程执行 │ └─────────┘ └─────────┘
|
流程总结
- 核心线程优先:任务来了先看核心线程是否已满
- 队列缓冲:核心线程满了,任务进入队列等待
- 扩容线程:队列满了,创建非核心线程处理 👉详解 ^expand-thread
- 拒绝任务:线程数达到最大且队列满,执行拒绝策略
注意:不是先扩容线程再入队,而是先入队再扩容!
任务队列类型
| 队列类型 |
特点 |
适用场景 |
| ArrayBlockingQueue |
有界数组队列,FIFO |
控制资源消耗,推荐使用 |
| LinkedBlockingQueue |
可选有界链表队列,默认无界 |
任务量可控时使用 |
| SynchronousQueue |
不存储元素,直接传递 |
CachedThreadPool 使用 |
| PriorityBlockingQueue |
优先级队列,无界 |
需要任务优先级时 |
| DelayQueue |
延迟队列 |
定时任务场景 |
1 2
| BlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(100);
|
四种拒绝策略
当任务无法被执行时(队列满 + 线程数达到最大),触发拒绝策略:
| 策略 |
行为 |
适用场景 |
| AbortPolicy |
抛出 RejectedExecutionException |
默认策略,快速失败 |
| CallerRunsPolicy |
由提交任务的线程执行 |
不丢弃任务,降级处理 |
| DiscardPolicy |
静默丢弃任务 |
允许丢失的场景 |
| DiscardOldestPolicy |
丢弃队列最老的任务,重新提交 |
新任务优先级更高 |
1 2 3 4 5 6 7
| RejectedExecutionHandler customHandler = (r, executor) -> { log.warn("任务被拒绝: {}", r.toString()); saveToDatabase(r); };
|
线程池状态(5种状态)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| ┌──────────┐ │ RUNNING │ ← 初始状态,接收新任务,处理队列任务 └────┬─────┘ │ shutdown() ▼ ┌──────────┐ │ SHUTDOWN │ ← 不接收新任务,继续处理队列任务 └────┬─────┘ │ 队列为空 && 工作线程为0 ▼ ┌──────────┐ │ TIDYING │ ← 所有任务终止,工作线程为0 └────┬─────┘ │ terminated() 执行完成 ▼ ┌──────────────┐ │ TERMINATED │ ← 线程池彻底终止 └──────────────┘
┌──────────┐ │ RUNNING │ └────┬─────┘ │ shutdownNow() ▼ ┌──────────┐ │ STOP │ ← 不接收新任务,中断正在执行的任务,清空队列 └────┬─────┘ │ 工作线程为0 ▼ ┌──────────┐ │ TIDYING │ └──────────┘
|
状态转换方法
| 方法 |
说明 |
shutdown() |
温和关闭,等待已提交任务完成 |
shutdownNow() |
立即关闭,尝试中断执行中的任务,返回未执行的任务列表 |
awaitTermination() |
阻塞等待线程池终止 |
1 2 3 4 5 6 7 8 9 10
| executor.shutdown(); try { if (!executor.awaitTermination(60, TimeUnit.SECONDS)) { executor.shutdownNow(); } } catch (InterruptedException e) { executor.shutdownNow(); Thread.currentThread().interrupt(); }
|
线程池监控
1 2 3 4 5 6 7 8 9 10
| ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(10);
System.out.println("核心线程数: " + executor.getCorePoolSize()); System.out.println("最大线程数: " + executor.getMaximumPoolSize()); 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());
|
相关链接
- 上一篇:01-线程池简介
- 下一篇:03-线程池类型