首先回顾一下java线程池的架构
进入正题,java线程池的执行步骤
1.创建线程池->submit或execute(提交任务)
上篇中说过,其实submit()底层调用的还是execute()。
看源码:
java线程池的顶级接口Executor下就一个方法execute();最终实现这个方法的是在ThreadPoolExecutor类中
2.添加任务(addWorker())
添加任务分四种情况:看源码中,addWorker()前执行了多个if语句,如下图:四个框就是分四种情况。
**第一种情况:**当前线程数小于核心线程数,如下这段代码:
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
执行addWorker(command, true)
参数:command:就是提交执行的任务
true:就代表走核心线程数,false:就代表走最大线程数=>看源码说话:
第二种情况: 当前线程数大于核心线程数的情况 ,就会执行workQueue.offer(command)
添加任务到阻塞队列,等待执行。如下这段代码:
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);
}
阻塞队列,用来存储等待执行的任务,决定了线程池的排队策略,有以下取值:
ArrayBlockingQueue;
LinkedBlockingQueue;
SynchronousQueue;
第三种情况: 如果当前线程数大于核心数并且阻塞队列也满了,但是小于最大线程数的情况,就会新建一个核心线程 然后addWorker(command, false)
上边说到了,参数false就是走的最大线程数。
第四种情况: 以上条件都不满足,则执行拒绝策略。reject(command)
记住拒绝策略有四种,划重点考试要考:
其中,AbortPolicy是默认的拒绝策略,就是直接抛异常,不信看源码说话:
CallerRunsPolicy();//如果添加到线程池失败,那么主线程会自己去执行该任务
DiscardOldestPolicy();//将最早进入队列的任务删,之后再尝试加入队列
DiscardPolicy();//丢任务不异常
3.执行任务(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 {
while (task != null || (task = getTask()) != null) {
w.lock();
// If pool is stopping, ensure thread is interrupted;
// if not, ensure thread is not interrupted. This
// requires a recheck in second case to deal with
// shutdownNow race while clearing interrupt
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
beforeExecute(wt, task);
Throwable thrown = null;
try {
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();
}
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly);
}
}
Runnable task = w.firstTask;
先把核心线程中的任务拿出来给task,
核心线程中的任务执行完才会执行阻塞队列中的任务,
while 条件语句中有task = getTask()
,就是从队列中取出任务并给task
。
下边有task.run();
就是执行任务。
4.执行完毕,流程结束(processWorkerExit())
看上边runWorker
源码中,最终的finally
里执行了processWorkerExit(w, completedAbruptly)
。
咱们进去看看源码:
private void processWorkerExit(Worker w, boolean completedAbruptly) {
if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
decrementWorkerCount();
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
completedTaskCount += w.completedTasks;
workers.remove(w);
} finally {
mainLock.unlock();
}
tryTerminate();
int c = ctl.get();
if (runStateLessThan(c, STOP)) {
if (!completedAbruptly) {
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
if (min == 0 && ! workQueue.isEmpty())
min = 1;
if (workerCountOf(c) >= min)
return; // replacement not needed
}
addWorker(null, false);
}
}
上边不用看,看最后是不是又回到addWorker
了。这就是线程池的重复利用,一条任务线程执行完有回到addWorker
,重复如此,直到天荒地老,海枯石烂。。。直到你关闭线程池调用,上一篇说过线程池关闭的方式。
5.总结
总结两张图,通俗易懂,自己画的,难看什么的无所谓吧。
执行流程:
四种情况:
纯属自己的理解,小白一个,说的不对的地方望见谅,评论提出修改。