使用多线程,必然要用到线程池,而ThreadPoolExecutor是java中线程池的重要实现类,理解ThreadPoolExecutor有助于我们更好地理解线程池、甚至去自定义自己的线程池。
基本使用
- 初始化线程池
Executor executor=new ThreadPoolExecutor(0,Integer.MAX_VALUE,60, TimeUnit.MILLISECONDS,new SynchronousQueue<Runnable>());
- 执行对应的任务
executor.execute(runnable);
原理图解
我们先来看一下ThreadPoolExecutor的工作原理图解,不明白不要紧,再继续看完源码分析便会明白了
源码分析
源码中,我们重点分析构造方法和几个重要的方法,execute、addWorker、runWorker和getTask
- 构造方法及参数
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler)
- int corePoolSize:核心线程数量,线程池中始终保持活跃的线程数量,不管有无任务,该数量的线程始终在运行或者等待运行
- int maximumPoolSize:线程池最大数量,线程中最大允许的线程数量,任务多于该数量时便会使用拒绝策略去拒绝执行任务
- long keepAliveTime、TimeUnit unit:保活时间,如果线程空闲时,还能保持活跃多久
- BlockingQueue workQueue:阻塞队列,如果任务现在无法直接执行,则会考虑放到队列中等待,运行中的任务执行完后再从队列中取出任务一一执行
- RejectedExecutionHandler handler:拒绝策略,如果收到的任务多于线程池最大数量,则会使用拒绝策略去拒绝执行
- execute执行任务 方法分析:对外提供的执行任务方法,也是线程池的入口方法
- 分析前,先介绍几个重要的数据结构
- Worker: 负责运行任务的中断控制和任务的管理,实现了runnable接口,持有一个Thread对象
- 运行时任务集合:private final HashSet workers = new HashSet<>();
- 阻塞队列:private final BlockingQueue workQueue;
- execute方法分析
- 首先判断核心线程数是否已满,未满则作为核心线程去执行
- 队列是否已满,未满则放到队列中等待执行
- 线程池是否已满,未满则分配非核心线程执行
- 否则使用拒绝策略
public void execute(Runnable command) {
int c = ctl.get();
//1. 运行任务数和核心线程数作比较
// 如果运行任务数少,则新建一个线程作为核心线程,并执行该任务
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
//2. 如果一个任务能够放到队列中
// 再次检查,当前线程池状态不是RUNNING,则回滚队列并使用拒绝策略
// 如果当前线程池线程为空,则添加该任务并执行
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);
}
//3. 如果能放到线程池中,则作为非核心线程去执行
//4. 否则使用拒绝策略进行拒绝
else if (!addWorker(command, false))
reject(command);
}
- worker之addWorker,添加任务
- 创建Worker和线程
- 将worker添加到集合中
- 让线程开始执行
private boolean addWorker(Runnable firstTask, boolean core) {
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
//1. 创建Worker和线程
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
//2. 将worker添加到集合中
int rs = runStateOf(ctl.get());
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
workers.add(w);
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
workerAdded = true;
}
} finally {
mainLock.unlock();
}
//3. 让线程开始执行
if (workerAdded) {
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
- worker之runWorker: 真正的执行任务,上一步的线程执行时,因为持有的是worker任务,所以线程执行会调用worker的runWorker方法
- 先执行当前任务
- 当前任务为空就通过getTask方法从阻塞队列中依次拿出任务去执行
- 任务执行分为三个小步骤
- 做执行前的准备工作
- 执行任务
- 做执行后的善后工作
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
//1. 此行为关键代码,循环获取任务并执行
while (task != null || (task = getTask()) != null) {
w.lock();
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 {
//处理worker退出
processWorkerExit(w, completedAbruptly);
}
}
- getTask方法:获取任务
- 检查一:线程终止,并且队列为空时,直接返回
- 检查二:工作线程数目以及是否超时
- 根据超时状态从队列中取出任务
private Runnable getTask() {
//标记是否超时
boolean timedOut = false; // Did the last poll() time out?
//无限循环从队列中获取任务,无任务时线程会阻塞等待任务,不消耗CPU资源
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
//1. 检查一:线程终止且队列为空,直接返回null
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
int wc = workerCountOf(c);
//标记线程是否可以超时停止
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
//2. 检查二:工作线程数目以及是否超时
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
//3. 从队列中取出任务并返回
try {
//poll方法:从BlockingQueue取出一个队首的对象,如果在指定时间内,
队列一旦有数据可取,则立即返回队列中的数据。否则知道时间超时还没有数据可取,返回null
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}