execute方法
1.工作线程数<核心线程数
2.否则将任务添加到阻塞队列
3.队列满了并且线程数小于最大线程,则创建线程
4.超过最大线程数,直接拒绝
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
//ctl高三位表示线程池状态,低29位表示线程数量
int c = ctl.get();
//工作线程数小于核心线程数
if (workerCountOf(c) < corePoolSize) {
/**
* addWorker失败原因
* 1.存在多线程并发
* 2.外部线程改变了线程池状态
*/
if (addWorker(command, true))
return;
c = ctl.get();
}
/**
* 工作线程数大于等于核心线程数或者addWorker失败,
* 判断线程池状态 如果是运行状态则添加任务到阻塞队列
*/
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
/**
* 重复判断主要是因为两个if之间可能被外部线程改变了线程池运行状态,这时需要移除新加到队列的任务
*
* */
if (! isRunning(recheck) && remove(command))
//移除成功则拒绝任务
reject(command);
/**
* 1.状态是运行状态
* 2.状态不是运行态并且移除任务失败
* 上述两种情况会判断线程数量是否为0,防止出现异常导致线程死亡
*/
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
/**
* 线程池不是运行状态(有可能被外部线程shutdown)则直接拒绝
* 队列满了,则判断线程数是否小于最大线程。
* 小于则开启新的线程处理任务,否则超过最大线程数则拒绝任务
*/
else if (!addWorker(command, false))
reject(command);
}
addWorker方法
主要作用就是将任务封装成worker对象并启动线程
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
/**
* 再次判断线程池状态
* 1.rs>SHUTDOWN
* 2.rs=SHUTDOWN && firstTask != null
* 3.rs=SHUTDOWN && workQueue.isEmpty()
* 上述三种情况都会失败
* 线程池状态为SHUTDOWN时只有提交的任务为null并且堵塞队列还有任务没有处理完时才会继续执行
* (也就是说线程池shutdown时,如果堵塞队列还有任务没有处理完毕则会继续执行,但是不会接收新的任务入队)
*/
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
//这个循环主要判断线程数量
for (;;) {
int wc = workerCountOf(c);
//判断线程池线程数量是否超出
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
//最重要的一个步骤:线程数量没有超出,通过CAS将线程数+1
if (compareAndIncrementWorkerCount(c))
break retry;
//CAS失败说明可能已经有线程改过ctl的值,重新获取ctl
c = ctl.get();
//判断线程池状态是否改变,改变了继续下一次循环
if (runStateOf(c) != rs)
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
}
boolean workerStarted = false;
boolean workerAdded = false;
ThreadPoolExecutor.Worker w = null;
try {
w = new ThreadPoolExecutor.Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
int rs = runStateOf(ctl.get());
/**
*再次检查线程池状态,防止创建worker过程中被外部线程修改
*/
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive())
throw new IllegalThreadStateException();
//将worker添加到hashset中,记录worker数量
workers.add(w);
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
workerAdded = true;
}
} finally {
mainLock.unlock();
}
//如果添加成功,主线程会启动worker线程
if (workerAdded) {
t.start();
workerStarted = true;
}
}
} finally {
//启动失败,进行后续操作
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
runWorker方法
线程启动会执行的具体方法
final void runWorker(ThreadPoolExecutor.Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
//首先执行worker内部的任务,执行结束会从队列里面获取任务执行
while (task != null || (task = getTask()) != null) {
//设置独占锁
w.lock();
/**
* 1.runStateAtLeast(ctl.get(), STOP)&&!wt.isInterrupted()成立
* 说明当前线程池状态>=stop&&当前线程没有设置中断状态,则需要给当前线程设置中断状态
* 2.Thread.interrupted() &&runStateAtLeast(ctl.get(), STOP)
* Thread.interrupted()表示获取当前中断状态并设置中断位为false
* 这里的主要目的在于将线程中断状态强制刷新为false
*/
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
//提供的扩展方法,可以自己实现
beforeExecute(wt, task);
Throwable thrown = null;
try {
//具体执行的run方法,注意执行task任务不会存在并发
task.run();
} catch (RuntimeException x) {
thrown = x; throw x;
} catch (Error x) {
thrown = x; throw x;
} catch (Throwable x) {
thrown = x; throw new Error(x);
} finally {
//提供的扩展方法,可以自己实现
afterExecute(task, thrown);
}
} finally {
task = null;
w.completedTasks++;
w.unlock();
}
}
//getTask()返回null会走正到这里,线程执行完正常退出
//否则表示执行task.run()出现异常
completedAbruptly = false;
} finally {
//completedAbruptly ==false 表示线程没有获取到任务 正常退出
//completedAbruptly == true 表示执行过程出现了异常 异常退出
processWorkerExit(w, completedAbruptly);
}
}
getTask方法
阻塞队列获取任务的方法
最大线程数采用poll方式获取任务,如果在指定时间获取不到任务,后面会执行线程退出
核心线程数默认采用take方式获取任务,获取不到任务会阻塞直到有任务进入阻塞队列
/**
* 返回null的情况
* 1.rs >= STOP线程池状态>=stop
* 2.rs == SHUTDOWN&&workQueue.isEmpty() 线程池状态是shutdown状态并且线程池空了
* 3.工作线程超过了最大线程数
* 4.工作线程超过了核心线程数,并且获取任务超时了可能被回收
* 5.allowCoreThreadTimeOut 设置为true,表示核心线程获取任务超时也会被回收
*/
private Runnable getTask() {
boolean timedOut = false;
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
/**
* 1.rs >= STOP 线程池状态大于等于stop
* 2.rs == SHUTDOWN && workQueue.isEmpty() 线程池状态等于shutdown并且队列为空
* cas方式对工作线程-1
* 上面两种情况表示线程池不用继续处理了,直接返回
*/
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
//走到这里说明线程池是running状态或者线程池是shutdown状态并且队列还有任务需要处理
int wc = workerCountOf(c);
//timed==true,表示核心线程也可以被回收,并且采用poll超时方式获取任务
//timed == false,否则会无限制等待方式获取任务
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
/**
* 1.wc > maximumPoolSize 回收最大线程
* timed && timedOut 表示以poll方式获取任务并且超时了
* 2.wc > 1 说明还有其他线程,则当前线程可以被回收
* wc==1 &&workQueue.isEmpty() 队列空了,当前线程也可以被回收
*/
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
try {
//timed==true 表示阻塞一段时间无论取到任务与否都会返回
//timed==false 表示无限制阻塞直到取到任务
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
//走到这说明获取任务超时了
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
allowCoreThreadTimeOut
可以设置核心线程数采用poll方式获取任务,也就是说在指定时间内获取不到任务核心线程数也可以被回收
public void allowCoreThreadTimeOut(boolean value) {
if (value && keepAliveTime <= 0)
throw new IllegalArgumentException("Core threads must have nonzero keep alive times");
if (value != allowCoreThreadTimeOut) {
allowCoreThreadTimeOut = value;
if (value)
interruptIdleWorkers();
}
}
另外说一下execute和submit区别?
1.submit会将提交的callable或runnable任务封装成futuretask,而execute不会。
2.execute执行出现异常会抛出,而submit不会抛出异常,需要拿到futuretask调用get方法才会抛出异常。