原理:http://www.importnew.com/19011.html#comment-578619
1、线程池状态
一个Volatile几个static final
volatile int runState;//当前池的状态,保证线程间可见性,下面是其可能的值
static final int RUNNING = 0;//创建后初始时处于此状态
static final int SHUTDOWN = 1;//调用shutdown,处此态:不接受新任务,等所有任务执行完毕
static final int STOP = 2;//shutdownNow,处此态,不接受新任务,尝试止正执行任务
static final int TERMINATED = 3;//池处shutdown/stop态,线程销毁、任务缓存队列清空、执行结束,池置此态
2、任务的执行
ThreadPoolExecutor类中部分成员变量
workQueue:任务缓存队列,存放等待执行的任务
ReentrantLock mainLock池的主要状态,状态改变使用此锁
HashSet<Worker> workers存放工作集
keepAliveTime:线程存活时间
allowCoreThreadTimeOut:是否容许为核心线程设置存活时间
corePoolSize:核心池大小,大于此、提交的任务会被放进任务缓存队列
maximunPoolSize:池max容忍的线程数
新任务数量增长速度大于处理任务的速度、此来补救
poolSize:当前线程数
RejectedExecutionHandler handler:任务拒绝策略
ThreadFactory threadFactory:线程工厂,用来创建线程
largestPoolSize:用来记录线程池中曾经出现过的最大线程数
completedTaskCount:用来记录已经执行完毕的任务个数
execute()
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();//任务为null空指针
if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) {
//当前线程数不小于核心池大小
if (runState == RUNNING && workQueue.offer(command)) {
//当前池处RUNNING态 && 任务放入任务缓存队列
if (runState != RUNNING || poolSize == 0)
//为了防止在将此任务添加进任务缓存队列时其他线程突然调用shutdown或shutdownNow关闭了池
//保证 添加到任务缓存队列中的任务得到处理
ensureQueuedTaskHandled(command);
}
else if (!addIfUnderMaximumPoolSize(command))
//执行addIfUnderMaximumPoolSize失败,任务拒绝处理
reject(command); // is shutdown or saturated
}
}
addIfUnderCorePoolSize
//当低于核心池大小时执行
private boolean addIfUnderCorePoolSize(Runnable firstTask) {
Thread t = null;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();//获取锁
try {
//线程池中线程数是否小于核心池大小(防止其他线程提交新任务)
//判断是否为running(万一其他线程调用shutdown或shutdownNow)
if (poolSize < corePoolSize && runState == RUNNING)
t = addThread(firstTask); //创建线程去执行firstTask任务
} finally {
mainLock.unlock();
}
if (t == null)
return false;//为空创建失败
t.start();
return true;
}
addThread
private Thread addThread(Runnable firstTask) {
Worker w = new Worker(firstTask);//用提交的任务创建worker
Thread t = threadFactory.newThread(w); //创建一个线程,执行任务
if (t != null) {
w.thread = t; //将创建的线程的引用赋值为w的成员变量
workers.add(w);//添加到工作集中
int nt = ++poolSize; //当前线程数加1
if (nt > largestPoolSize)
largestPoolSize = nt;
}
return t;
}
worker类实现略
总结:
1、池中数<corePoolSize,来任务执行
2、池中数>=corePoolSize,来任务,添加缓存队列,成功 任务等待空闲线程将其取出执行
添加失败(任务缓存队列满)尝试创建新线程去执行
3、池中数>=maximumPoolSize,采取任务拒绝策略
4、池中数>corePoolSize
某线程空闲时间超过keepAliveTime,线程终止,直到池中数<=cPS
如果容许为核心池设置存活时间,池中线程空闲时间超过keepAliveTime,终止
3、线程池中线程的初始化
创建池后,提交任务后创建线程
需创建后立即创建线程:
1、prestartCoreThread初始化一个核心线程
2、prestartAllCoreThreads初始化所有核心线程
public boolean prestartCoreThread() {
return addIfUnderCorePoolSize(null); //注意传进去的参数是null
}
public int prestartAllCoreThreads() {
int n = 0;
while (addIfUnderCorePoolSize(null))//注意传进去的参数是null
++n;
return n;
}
4、任务缓存队列及排队策略
1)ArrayBlockingQueue:基于数组的先进先出队列,此队列创建时必须指定大小;
2)LinkedBlockingQueue:基于链表的先进先出队列,如果创建时没有指定此队列大小,则默认为Integer.MAX_VALUE;
3)synchronousQueue:这个队列比较特殊,它不会保存提交的任务,而是将直接新建一个线程来执行新来的任务
5、任务拒绝策略
任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize
ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
ThreadPoolExecutor.CallerRunsPolicy:由调用线程处理该任务
6、线程池的关闭
7、池容量的动态调整
setCorePoolSize:设置核心池大小
setMaximumPoolSize:设置线程池最大能创建的线程数目大小
创建线程池:推荐方法
Executors.newCachedThreadPool(); //创建一个缓冲池,缓冲池容量大小为Integer.MAX_VALUE
Executors.newSingleThreadExecutor(); //创建容量为1的缓冲池
Executors.newFixedThreadPool(int); //创建固定容量大小的缓冲池
……
http://www.importnew.com/19011.html#comment-578619
后语:
对博客的一些提炼,代码部分还有一些没有转过来,感谢大神的分享