线程池类型 | 描述 |
---|---|
newFixedThreadPool | 一个定长线程池,可控制线程最大并发数 |
newCachedThreadPool | 一个可缓存的线程池 |
newSingleThreadExecutor | 一个单线程的线程池,用唯一工作线程执行任务 |
newScheduledThreadPool | 一个定长线程池,支持周期性任务执行 |
线程池通过 ThreadPoolExecutor 方式创建的原因:
Executors创建的线程池底层也是调用 ThreadPoolExecutor ,只不过使用不同的参数,队列,拒绝策略等。如果使用不当,会造成资源耗尽问题;
直接使用 ThreadPoolExecutor 让使用者更加清楚线程池使用规则,避免风险
常见问题:
- newFixedThreadPool 和 newSingleThreadExecutor:队列使用LinkedBlockingQueue,队列长度为Integer.MAX_VALUE, 可能造成堆积,导致OOM
- newCachedThreadPool 和 newScheduledThreadPool:线程池里面允许最大线程数是Integer.MAX_VALUE,可能会创建过多线程导致OOM
ThreadPoolTaskExecutor执行步骤:
-
查看核心线程池corePoolSize是否已满,不满就创建一条线程执行任务,否则执行第二步。
坑: 在刚创建线程池的时候不会立即启动,有任务提交时才开始创建线程并逐步使线程数目达到corePoolSize
-
查看阻塞队列是否已满,不满就将任务存储在阻塞队列中,否则执行第三步
坑: 当核心线程数已满,且阻塞队列也满时,才判断当前线程数是否小于最大线程数,决定是否创建新线程
-
查看线程池是否已满,即是否达到最大线程池数,不满就创建一条线程执行任务,否则就按照策略处理无法执行的任务
核心线程参数设置参考:
根据项目需求判断时IO密集型还是CPU密集型。
- CPU密集型项目主要消耗CPU资源,所以建议设置为跟CPU核数一样或者+1;
- IO密集型项目,系统会用大部分时间来处理I/O交互,这段时间不会占用CPU,所以线程数可以配置为2倍的CPU核数
以上参数仅作为参考,最好根据压测情况进一步优化参数。
线程池的拒绝队列:
拒绝策略 | 概述 |
---|---|
AbortPolicy | 默认策略,如果线程池队列满,则丢掉这个任务。并且抛出RejectedExecutionException异常 |
CallerRunsPolicy | 交由调用方线程运行,如果添加到线程池失败,那么主线程会自己去执行这个任务 |
DiscardPolicy | 线程池队列已满,会直接丢掉这个任务且不会有任何异常 |
DiscardOldestPolicy | 丢弃掉线程池中最老的任务,队列满了会将最早进入队列的任务删掉,腾出空间。再尝试加入线程池队列 |