说明:文章内容均为基于个人理解,如有错误,请见谅并指出,大家一同进步,多谢 ^ _ ^。
线程池原理:
通过初始创建好一定数目的线程数量,来达到持续不断地任务并行处理的效果,并因此减少不断创建和销毁线程的开销。
线程池核心实现:
线程池的核心实现就在于ThreadPoolExecutor类。
我们先看看其继承关系
public class ThreadPoolExecutor extends AbstractExecutorService
ThreadPoolExecutor继承抽象类AbstractExecutorService
public abstract class AbstractExecutorService implements ExecutorService
AbstractExecutorService继承接口ExecutorService
public interface ExecutorService extends Executor
ExecutorService接口继承Executor接口
由此可见,Executor是顶层接口,而接口中只声明了一个方法。
public interface Executor {
void execute(Runnable command);
}
那我们先来看看ThreadPoolExecutor类的这个execute的实现,其功能是啥?就是执行提交到线程池的Runnable任务的。在代码中我稍作注释,然后在后边再做一个说明。
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))
reject(command);
}
线程池执行核心
可以说,线程池执行任务的核心在这里。
首先在线程数少于我们设置的核心线程数时,new新线程(这一工作addWorker中去做)。
如果活跃线程不少于设置的核心线程数,则将任务添加到任务队列中。只是,如果添加成功,需要再次检查,线程池是否还处于Running状态(如果不为Running,就要把加入到队列中的任务移出,并reject该任务),以及检查活跃的工作者线程数是否为0了(如果为0,创建一个新线程)。
如果任务队列已满,任务没法加入等待队列,也尝试创建新线程运行该任务。
我们看看addWorker实现
private boolean addWorker(Runnable firstTask, boolean core) {
// retry 这段代码在于检查当前线程池状态以及根据给予的线程池的核心线程数或者最大线程数界限来确定是否可以添加一
// 个worker,也就是再添加一个工作线程。如果可以添加,则工作线程数计数器也做相应调整。如果能够添加一个新线程,