【JUC】线程池学习与使用
一、线程池基本原理
1、线程池执行策略
线程池分为核心线程池,线程池的最大容量,还有等待任务的队列,提交一个任务,如果核心线程没有满,就创建一个线程,如果满了,就是会加入等待队列,如果等待队列满了,就会增加线程,如果达到最大线程数量,如果都达到最大线程数量,就会按照一些丢弃的策略进行处理。
2、线程池七大基本参数
public ThreadPoolExecutor(
int corePoolSize, // 核心线程数
int maximumPoolSize, // 最大线程数
long keepAliveTime, // 空闲线程存活时间
TimeUnit unit, // 时间单位
BlockingQueue<Runnable> workQueue, // 工作队列
ThreadFactory threadFactory, // 线程工厂
RejectedExecutionHandler handler // 拒绝策略
)- corePoolSize: 线程池中始终保持存活的线程数量。 即使线程空闲也不会被回收(除非设置allowCoreThreadTimeOut)。 根据CPU密集型或IO密集型任务合理设置
- CPU密集型任务:计算量大,CPU占用率高,线程大部分时间在执行计算(逻辑处理多)
- IO密集型任务:等待时间长,CPU空闲多,线程大部分时间在等待(文件读取)
- maximumPoolSize:线程池允许创建的最大线程数量。当工作队列满且核心线程都在忙时,会创建新线程。通常设置为corePoolSize的2-3倍。
- 工作队列(workQueue):常用队列有如下这几种:LInkedBlockingQueue、ArrayBlockingQUeue、SynchronizeQUeue、DElayQUeue、PriorityBlockingQueue。都是线程安全的。
| 队列类型 | 特点 | 适用场景 |
|---|---|---|
| ArrayBlockingQueue | 有界队列,FIFO,必须指定大小 | 需要控制队列大小的场景 |
| LinkedBlockingQueue | 可选有界/无界,FIFO,不指定大小是Integer.MAX_VALUE | 默认选择,吞吐量高 |
| SynchronousQueue | 不存储元素,直接传递,但是新的进来时若之前有任务未消费会阻塞 | 高并发,任务处理快 |
| PriorityBlockingQueue | 优先级队列 | 需要任务优先级的场景 |
| DelayQueue | 基于时间的延迟队列,元素在指定延迟时间后才能被取出 | 可以用定时任务调度、缓存过期、会话超时管理 |
- 拒绝策略(RejectedExecutionHandler)当线程池和工作队列都满时,采取的处理策略:
| 策略名称 | 行为 | 异常处理 |
|---|---|---|
| AbortPolicy(默认) | 抛出RejectedExecutionException | 抛出异常 |
| CallerRunsPolicy | 由调用者线程执行任务 | 不抛异常 |
| DiscardPolicy | 直接丢弃任务,不抛异常 | 静默丢弃 |
| DiscardOldestPolicy | 丢弃队列中最老的任务,然后重试提交 | 可能丢失任务 |
| 自定义拒绝策略 | 通过实现接口可以自定义任务拒绝策略 |
二、线程池创建方法
1、Excutors
不推荐使用Executors工厂方法,因为不能决定内部关键参数,会导致OOM等等问题:Executors创建的四种常见线程池:FixedThreadPool(固定大小线程池)、SingleThreadExecutor(单线程线程池)、CachedThreadPool(缓存线程池)、ScheduledThreadPool(定时/周期线程池)
FixedThreadPool | 核心/最大:nThreads | 队列:LinkedBlockingQueue (无界) 存活:0 (永不过期) | 特点: 固定线程数,任务排队执行 风险: 无界队列可能堆积大量任务导致OOM |
SingleThreadExecutor | 核心/最大:1 | 队列:LinkedBlockingQueue (无界) 存活:0 (永不过期) | 特点: 单线程顺序执行任务 风险: 无界队列可能堆积大量任务导致OOM |
CachedThreadPool | 核心:0 最大:Integer.MAX_VALUE | 队列:SynchronousQueue (同步移交) 存活:60秒 | 特点: 线程数弹性,适合短期异步任务 风险: 可能创建大量线程导致资源耗尽 |
ScheduledThreadPool | 核心:corePoolSize 最大:Integer.MAX_VALUE | 队列:DelayedWorkQueue (延迟队列) 存活:0 (永不过期) | 特点: 支持定时和周期性任务 风险: 延迟任务堆积可能导致内存问题 |

2、ThreadPoolTaskExecutor
Executors 工具类创建的四种线程池本质上都是调用 ThreadPoolExecutor 构造函数,只是预设了不同的参数组合。在实际 Spring 工程中,推荐直接使用 ThreadPoolTaskExecutor,这是 Spring 对 ThreadPoolExecutor 的增强封装,与 Spring 生态无缝集成。
1、ThreadPoolTaskExecutor实现了 Spring 的 TaskExecutor 接口,支持 @Async 注解、@EnableAsync 配置。
2、支持 properties/yaml 配置文件,可通过 @ConfigurationProperties 批量配置多个线程池,统一管理更清晰。
3、Spring 容器关闭时会自动执行 shutdown(),支持等待任务完成的 awaitTermination 配置,避免任务丢失。
四、线程池任务撤回与停机
1、线程池撤回就直接调用.canle()函数就行。CompletableFuture.supplyAsync().cancel();
2、停机就是上面说的通过shutdown()函数进行,但是尽量不用shutdownNow(),这个会直接将正在进行的任务打断,它试图终止线程的方法是通过调用 Thread.interrupt() 方法来实现,但interrupt只有对sleep、wait等状态下的线程能够抛出异常,才有用。
五、总结
Java线程池是多线程编程的核心组件,合理配置和使用线程池能显著提升应用性能。我们在使用时尽量考虑好使用场景再去创建。