1.状态表示:
ThreadPoolExecutor 使用 int 的高 3 位来表示线程池状态,低 29 位表示线程数量
状态名 |
高
3
位
|
接收新任
务
|
处理阻塞队列任
务
| 说明 |
RUNNING | 111 | 是 | 是 | 初始状态 |
SHUTDOWN | 000 | 否 | 是 |
不会接收新任务,但会处理阻塞队列剩余任务
|
STOP | 001 | 否 | 否 |
会中断正在执行的任务,并抛弃阻塞队列任务
|
TIDYING | 010 | - | - |
任务全执行完毕,活动线程为0
即将进入
终结
|
TERMINATED | 011 | - | - | 终结状态 |
信息存储在一个原子变量 ctl
中,目的是将线程池状态与线程个数合二为一,这样就可以用一次
cas
原子操作
进行赋值。
2.构造方法属性:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
corePoolSize 核心线程数目 (最多保留的线程数)
maximumPoolSize 最大线程数目
keepAliveTime 生存时间 - 针对救急线程
unit 时间单位 - 针对救急线程
workQueue 阻塞队列
threadFactory 线程工厂 - 可以为线程创建时起名
handler 拒绝策略
最大线程数量 = 核心数 + 救急数.
处理过程:线程池中刚开始没有线程,当一个任务提交给线程池后,线程池会创建一个新线程来执行务。 当核心线程数达到 corePoolSize的初始值而且 没有其他线程空闲,如果这时再加入任务,新加的任务会被加入 阻塞workQueue 队列排队,直到有空闲的线程。 如果队列选择了有界队列,那么任务超过了队列大小时,就会创建救急线程来处理任务(maximumPoolSize - corePoolSize ) 如果队列没有使用有界队列就不会创建救急线程而是采用拒绝策略. 当线程到达 maximumPoolSize 仍然有新任务这时会执行拒绝策略。拒绝策略 jdk 提供了 4 种实现,AbortPolicy 让调用者抛出RejectedExecutionException 异常,这是默认策略DiscardPolicy 放弃本次任务DiscardOldestPolicy 放弃队列中最早的任务,本任务取而代之.
核心线程和救急线程对比:
1.救急线程是有存活时间的 keepAliveTime
,而核心线程一旦创建就会一直在线程池中.
2.两者的创建机理是不同的.
3.JDK Executors
类中提供了众多工厂方法来创建各种用途的线程池.
1.newFixedThreadPool :
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
核心线程数 == 最大线程数(没有救急线程被创建),因此也无需超时时间
阻塞队列是无界的,可以放任意数量的任务.
2.newCachedThreadPool
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
特点:核心线程数是 0,最大线程数是
Integer.MAX_VALUE
,救急线程的空闲生存时间是
60s
,意味着
全部都是救急线程(
60s
后可以回收)
队列采用了
SynchronousQueue
实现特点是,它没有容量,没有线程来取是放不进去的.
3.
newSingleThreadExecutor
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
线程数固定为
1
,任务数多于
1
时,会放入无界队列排队。任务执行完毕,这唯一的线程
也不会被释放。
3.执行方法:
// 执行任务void execute ( Runnable command );// 提交任务 task ,用返回值 Future 获得任务执行结果< T > Future < T > submit ( Callable < T > task );// 提交 tasks 中所有任务< T > List < Future < T >> invokeAll ( Collection <? extends Callable < T >> tasks )throws InterruptedException ;// 提交 tasks 中所有任务,带超时时间< T > List < Future < T >> invokeAll ( Collection <? extends Callable < T >> tasks ,long timeout , TimeUnit unit )throws InterruptedException ;// 提交 tasks 中所有任务,哪个任务先成功执行完毕,返回此任务执行结果,其它任务取消< T > T invokeAny ( Collection <? extends Callable < T >> tasks )throws InterruptedException , ExecutionException ;// 提交 tasks 中所有任务,哪个任务先成功执行完毕,返回此任务执行结果,其它任务取消,带超时时间< T > T invokeAny ( Collection <? extends Callable < T >> tasks ,long timeout , TimeUnit unit )throws InterruptedException , ExecutionException , TimeoutException ;
4.关闭线程池
1.shutdown
线程池状态变为 SHUTDOWN 不会接收新任务 , 但已提交任务会执行完 , 此方法不会阻塞调用线程的执行 。
在调用shutdown之后再执行新的任务就会报错,但是之前的所有任务都会执行:
2.shutdownNow
线程池状态变为 STOP ,不会接收新任务 , 会将队列中的任务返回并用 interrupt 的方式中断正在执行的任务