1:先看下线程池属性配置
public ThreadPoolExecutor(int corePoolSize, //核心线程池个数
int maximumPoolSize, //最大线程池个数
long keepAliveTime, //非核心线程存活时间
TimeUnit unit, //时间格式
BlockingQueue<Runnable> workQueue, //存放Runnable的工作队列
ThreadFactory threadFactory, //创建线程所需工厂
RejectedExecutionHandler handler //超出workQueue最大等待队列与maximumPoolSize之和会回调此接口)
1:corePoolSize(核心线程池个数)核心线程会一直存在,并且一直运行,知道关闭线程池或者线程被中断。
2:maximumPoolSize(最大线程池个数)就是该线程池允许创建线程的最大个数。
3:unit(时间格式)时,分,秒等。
4:workQueue(存放Runnable的工作队列)
(1)当corePoolSize为5,workQueue的长度为5,则同时创建5个核心线程取执行这5个工作队列。也就是说workQueue的长度小于等于corePoolSize时会创建workQueue长度的线程取执行工作队列(我使用JDK1.8是这样的,1.6的不确定)。
(2)当工作队列workQueue的size大于核心线程池数并且小于阻塞队列的个数(用ArrayBlockingQueue可以设置等待队列的个数),则只会创建全部的核心线程取执行工作队列里的数据,其他队列处于阻塞状态。
(3)当工作队列workQueue的size大于核心线程池数并且大于等待队列的个数,则会新建线程执行队列。新建线程个数=工作队列个数 - 核心线程池数 - 阻塞队列数。
(3)当工作队列workQueue的size > (maximumPoolSize+工作队阻塞待个数) 会回调 handler 将超出的队列抛出。需要在回调处将队列重新加到线程池里,否则该队里的功能将不再执行。此时回调与执行execute在同一个线程,若是主线程,队列一直处于超出状态,主线程会卡死。
2:内部执行原理
(1)调用执行方法
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) { //小于核心线程个数
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) { // 大于核心线程数量,核心线程开启失败,并且阻塞队列未满
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false)) // 当工作队列workQueue的size > (maximumPoolSize+工作队列阻塞个数)
reject(command);
}
(2)addWorker方法
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
/**
走出该死循环并继续执行该方法之后代码条件是:小于核心线程数或者大于核心线程数与阻塞数之和,或者核心线程未开启
*/
for (;;) {
…… //代码省略
}
……
try {
w = new Worker(firstTask); //创建线程,将该工作任务绑定到该线程
final Thread t = w.thread;
if (t != null) {
……
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
workers.add(w); //将创建的线程存入线程队列里
……
}
} finally {
mainLock.unlock();
}
if (workerAdded) {
t.start(); //开启线程
workerStarted = true;
}
}
} …….
return workerStarted;
}
(3)Worker 类
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this); //创建线程
}
(4)当线程启动时会执行Worker 类中的run方法
public void run() {
runWorker(this); //继续跟踪该方法
}
(5)runWorker方法
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
//首先执行该线程绑定的任务。而getTask()方法是有关核心线程如何回收重用的,
while (task != null || (task = getTask()) != null) {
……
} finally {
processWorkerExit(w, completedAbruptly);
}
}
(6)getTask()方法
private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?
//该循环是死循环,当为核心线程时,队列为空,则一直循环,不为空则返回给runWorker(Worker w) 中的while循环,当非核心线程,则存活到keepAliveTime时间,会跳出该循环,同时也满足退出runWorker(Worker w) 中的while循环,所以该线程结束生命周期。
for (;;) {
……
try {
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : //当为非核心线程,执行该代码
workQueue.take(); //当为核心线程执行该行。一直从队列拿数据,所以外面只要往线程池加队列,就会立马执行。所以核心线程一直死循环存在。解释了核心线程为什么能够被重新利用
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}