ThreadPoolExecutor是创建线程池的一种方式,之前一直用Executors
创建线程池后来发现不提倡用了,提倡用ThreadPoolExecutor去创建那就讲解一下吧。
一:线程池特性
1:线程池状态
线程池状态 | 说明 |
---|---|
RUNNING | 允许提交并处理任务 |
SHUTDOWN | 不允许提交新的任务,但是会处理完已提交的任务 |
STOP | 不允许提交新的任务,也不会处理阻塞队列中未执行的任务,并设置正在执行的线程的中断标志位 |
TIDYING | 所有任务执行完毕,池中工作的线程数为0,等待执行terminated()勾子方法 |
TERMINATED | terminated()勾子方法执行完毕 |
- 线程池的
shutdown()
方法,将线程池由RUNNING
(运行状态)转换为SHUTDOWN
状态。 - 线程池的
shutdownNow()
方法,将线程池由RUNNING
或SHUTDOWN
状态转换为STOP
状态。 SHUTDOWN
状态 和STOP
状态 先会转变为TIDYING
状态,最终都会变为TERMINATED
。- 其实
shutdown()
和shutdownNow()
并不会马上对线程池完成停止。这个可以查看阻塞队列BlockingQueue(FIFO)[本人博客]代码实操就可以看出。
2:构造函数
ThreadPoolExecutor继承自AbstractExecutorService
,而AbstractExecutorService
实现了ExecutorService
接口。
接下来我们分别讲解这些参数的含义。
2.1:线程池工作原理
首先先说下简单的三个:
- corePoolSize :线程池中核心线程数的最大值。
- maximumPoolSize :线程池中能拥有最多线程数。
- workQueue:用于缓存任务的阻塞队列。
当调用线程池execute()
方法添加一个任务时,线程池会做如下判断:
- 如果有空闲线程,则直接执行该任务。
- 如果没有空闲线程,且当前运行的线程数少于
corePoolSize
,则创建新的线程执行该任务。 - 如果没有空闲线程,且当前的线程数等于
corePoolSize
,同时阻塞队列未满,则将任务入队列,而不添加新的线程。 - 如果没有空闲线程,且阻塞队列已满,同时池中的线程数小于
maximumPoolSize
,则创建新的线程执行任务。 - 如果没有空闲线程,且阻塞队列已满,同时池中的线程数等于
maximumPoolSize
,则根据构造函数中的handler
指定的策略来拒绝新的任务。
2.2:KeepAliveTime
- keepAliveTime :表示空闲线程的存活时间。
- TimeUnit unit :表示keepAliveTime的单位。
当一个线程无事可做,超过一定的时间(keepAliveTime
)时,线程池会判断,如果当前运行的线程数大于 corePoolSize
,那么这个线程就被停掉。所以线程池的所有任务完成后,它最终会收缩到 corePoolSize
的大小。
注意:如果线程池设置了allowCoreThreadTimeout
参数为true(默认false),那么当空闲线程超过keepaliveTime
后直接停掉。(不会判断线程数是否大于corePoolSize
)即:最终线程数会变为0。
2.3:workQueue 任务队列
- workQueue :它决定了缓存任务的排队策略
ThreadPoolExecutor线程池推荐了三种等待队列:
- SynchronousQueue
- LinkedBlockingQueue
- ArrayBlockingQueue
2.3.1:有界队列
SynchronousQueue(可看本人博客) :一个不存储元素的阻塞队列,每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于 阻塞状态,吞吐量通常要高于LinkedBlockingQueue
,静态工厂方法 Executors.newCachedThreadPool
使用了这个队列。
ArrayBlockingQueue(可看本人博客):一个由数组支持的有界阻塞队列。此队列按 FIFO(先进先出)原则对元素进行排序。一旦创建了这样的缓存区,就不能再增加其容量。试图向已满队列中放入元素会导致操作受阻塞;试图从空队列中提取元素将导致类似阻塞。
2.3.2:无界队列
- LinkedBlockingQueue(可看本人博客):基于链表结构的无界阻塞队列,它可以指定容量也可以不指定容量(实际上任何无限容量的队列/栈都是有容量的,这个容量就是
Integer.MAX_VALUE
)。 - PriorityBlockingQueue(可看本人博客):是一个按照优先级进行内部元素排序的无界阻塞队列。队列中的元素必须实现
Comparable
接口,这样才能通过实现compareTo()
方法进行排序。优先级最高的元素将始终排在队列的头部;PriorityBlockingQueue
不会保证优先级一样的元素的排序。
注意:keepAliveTime和maximumPoolSize
及BlockingQueue
的类型均有关系。如果BlockingQueue
是无界的,那么永远不会触发maximumPoolSize
,自然keepAliveTime
也就没有了意义。
2.4:threadFactory
- threadFactory :指定创建线程的工厂。(可以不指定)
如果不指定线程工厂时,ThreadPoolExecutor 会使用ThreadPoolExecutor.defaultThreadFactory
创建线程。默认工厂创建的线程:同属于相同的线程组,具有同为 Thread.NORM_PRIORITY
的优先级,以及名为 “pool-XXX-thread-”