一、浩言
努力、努力、努力!!!
二、内容
2.1)、固定参数
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
- corePoolSize:指定了线程池中的线程数量。
- maximumPoolSize:指定了线程池中的最大线程数量。
- keepAliveTime:当前线程池数量超过corePoolSize时,多余的空闲线程存活时间,即,超过corePoolSize的空闲线程,在多长时间内会被销毁。
- unit:keepAliveTime的单位。
- workQueue:任务队列,被提交但尚未被执行的任务。
- threadFactory:线程工厂,用于创建线程,一般用默认的即可。
- handler:拒绝策略。当任务太多来不及处理,如何拒绝任务。
对于任务队列可以分为以下几种
直接提交的队列:该功能由SynchronousQueue对象提供,SynchronizedQueue是一个特殊的BlockingQueue。SynchronousQueue没有容量,每一个插入操作都要等待一个相应的删除操作,反之每一个删除操作都要等待对应的插入。SynchronizedQueue不保存任务,它总是将任务提交给线程执行,如果没有空闲的线程,则尝试创建新的线程,如果线程数量已经达到最大值,则执行拒绝策略。
有界的队列:有界的任务队列可以使用ArrayBlockingQueue实现。ArrayBlockingQueue的构造函数必须带一个容量参数,表示该队列的最大容量;当使用有界的任务队列时,若有新的任务需要执行,如果线程池的实际线程数量小于corePoolSize,则会优先创建新的线程,若大雨corePoolSize,则会将新的任务加入等待队列。若等待队列已满,无法加入,则在总线程数不大于maximumPoolSize的前提下,创建新的线程执行任务。若大于maximumPoolSize,则执行拒绝策略;所以,有界队列当任务队列装满时,才可能将线程数量提升到corePoolSize以上。
无界的队列:无界的任务队列使用LinkedBlockingQueue类实现,与有界队列相比,除非系统资源耗尽,否则无界的任务队列不存在任务入队失败的情况,当有新的任务到来,系统的线程数小于corePoolSize时,线程池会生成新的线程执行任务,但当系统的线程数到达corePoolSize后,就不会继续增加。若后续仍有新的任务加入,而又没有空闲的线程资源,则任务直接进入队列等待,若任务创建和处理的速度差异很大,无界队列会保持快速增长,直到耗尽系统内存。
优先任务队列:优先任务队列是带有执行优先级的队列,它通过PriorityBlockingQueue实现,可以控制任务的执行先后顺序,是一个特殊的无界队列。无论是有界队列ArrayBlockingQueue,还是无界队列LinkedBlockingQueue都是按照先进先出算法处理任务的。而PriorityBlockingQueue则可以根据任务自身的优先级顺序先后执行,在确保系统性能的同时,也能有很好的质量保证
2.2)、相关线程说明
2.2.1)、固定线程数-newFixedThreadPool
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue());
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue(),
threadFactory);
newFixedThreadPool使用了固定数量达线程数,队列使用了无界的LinkedBlockingQueue队列,因此,线程数据不存在变化,在到达固定线程后,新来的线程都放入队列,如果新加入的线程很多,则会一直加入队列,直到系统资源耗尽。
2.2.2)、单列线程池-newSingleThreadScheduledExecutor
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue()));
}
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue(),
threadFactory));
}
newSingleThreadExecutor和newFixedThreadPool差不多,只是newSingleThreadExecutor固定一个线程。
2.2.3)、可缓存线程-newCachedThreadPool
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue());
}
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue(),
threadFactory);
}
newCachedThreadPool中的corePoolSize为0,而maximumPoolSize无穷达的线程池,这说明在没有任务的时候线程池中的线程数为0;当有任务提交的时候,该线程池会使用空闲的线程执行任务。若无空闲线程,则将任务加入到SynchronousQueue,SynchronousQueue是一种提交队列,当入队一个线程后会阻塞,一直等到被take后,才会存放下一个线程,因此,它总是会迫使线程池中增加新的线程执行任务。当任务执行完毕后,空闲的线程会在指定的时间内被回收。当有很多大量线程被提交,任务执行不够快时,会开启等量的线程,这样会耗尽系统的资源。
2.3)、拒绝策略
- AbortPolicy策略:该策略直接抛出异常,阻止系统正常允许。
- CallerRunsPolicy策略:只要线程池未关闭,该策略直接在调用者线程中,运行当前被丢弃的任务。
- DiscardOledestPolicy策略:该策略将丢弃最老的一个请求,也就是即将被执行的一个任务,并尝试再次提交当前任务。
- DiscardPolicy策略:该策略默默地丢弃无法处理的任务,不予任何处理。
三、线程池ThreadPoolExecutor状态
源码中的注释解释如下:
RUNNING: Accept new tasks and process queued tasks
运行中:接收新的任务并且处理已经入队的任务
SHUTDOWN: Don't accept new tasks, but process queued tasks
关闭:不接收新的任务,但是处理已经入队的任务
STOP: Don't accept new tasks, don't process queued tasks,and interrupt in-progress tasks
停止:不接收新的任务,不处理已经入队的任务,并且中断进行中的任务
TIDYING: All tasks have terminated, workerCount is zero, the thread transitioning to state TIDYING will run the
terminated() hook method
整理:所有任务已经执行完成,workerCount大小是0,线程状态切到TIDYING ,将会运行 terminated() 回调方法
TERMINATED: terminated() has completed
完成,terminated() 执行完成
源码
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
// runState is stored in the high-order bits
private static final int RUNNING = -1 << COUNT_BITS;
private static final int SHUTDOWN = 0 << COUNT_BITS;
private static final int STOP = 1 << COUNT_BITS;
private static final int TIDYING = 2 << COUNT_BITS;
private static final int TERMINATED = 3 << COUNT_BITS;
// Packing and unpacking ctl
private static int runStateOf(int c) { return c & ~CAPACITY; }
private static int workerCountOf(int c) { return c & CAPACITY; }
private static int ctlOf(int rs, int wc) { return rs | wc; }
其中ctl属性是控制状态,它有两层概念:
workerCount, indicating the effective number of threads
runState, indicating whether running, shutting down etc
workCount:有效的线程数量
runState:当前线程池的状态
ctl中有29位来表示workerCount,3位来表示当前线程池的状态。
对于这里的位运算我还是没弄清楚,我自己尝试打印了下相关变量数据,但是觉得并没有什么用,具体计算还是位运算。
四、问答
1)问:当线程数达到coreSize后,没有请求后,coreSize个线程会被回收么?怎么回收coreSize的线程
首先,不会回收coreSize的线程;keepAliveTime是针对coreSize < n < maximumPoolSize的线程,空闲超过这个时间就会被回收超过coreSize的线程数量;
如果想要回收coreSize的线程数量,可以设置ThreadPoolExecutor属性allowCoreThreadTimeOut,源码中如下:
/**
* If false (default), core threads stay alive even when idle.
* If true, core threads use keepAliveTime to time out waiting
* for work.
*/
private volatile boolean allowCoreThreadTimeOut;