这里了解ThreadPoolExecutor的工作机制
void execute(Runnable command);
public interface ExecutorService extends Executor {
// 关闭线程池
void shutdown(); // 等到任务执行完成后关闭
List<Runnable> shutdownNow(); // 立刻关闭
// 判断线程池是否关闭
boolean isShutdown();
boolean isTerminated();
boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException;
// 提交一个有返回值的异步任务
<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);
// 批量提交异步任务
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) // 返回所有异步任务的future
throws InterruptedException;
<T> T invokeAny(Collection<? extends Callable<T>> tasks) // 如果有一个异步任务执行完成,立刻返回
throws InterruptedException, ExecutionException;
}
public abstract class AbstractExecutorService implements ExecutorService {
public class ThreadPoolExecutor extends AbstractExecutorService {
总结:
submit方法:它的内部是调用了execute方法,同时将异步任务封装到FutureTask中,然后调用FutureTask来获取返回值
// ThreadPoolExecutor中的submit方法继承自AbstractExecutorService类中,它是ThreadPoolExecutor的直接父类
public Future<?> submit(Runnable task) {
// 如果任务对象为null,抛出空指针异常
if (task == null)
throw new NullPointerException();
// 创建一个新的FutureTask对象
RunnableFuture<Void> ftask = newTaskFor(task, null);
// 执行futureTask对象
execute(ftask);
// 返回futureTask对象
return ftask;
}
// newTaskFor方法,在submit方法中被调用,参数runnable是要执行的任务,参数value是默认的返回值
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
return new FutureTask<T>(runnable, value);
}
execute方法是执行异步任务的核心方法
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
// 获取线程池状态
int c = ctl.get();
// 1. 如果当前线程小于核心线程数,创建新线程来执行任务
if (workerCountOf(c) < corePoolSize) {
// addWorker方法,创建新线程并且执行任务
if (addWorker(command, true))
return;
// 如果创建线程失败,重新获取线程池状态
c = ctl.get();
}
// 2. 把任务添加到工作队列中,需要先判断线程池是不是正在运行
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
// 如果添加成功,再次检查线程池的状态,如果不是正在运行,从对列中移除任务,然后执行拒绝策略
if (! isRunning(recheck) && remove(command))
reject(command);
// 3. 添加新的线程执行任务
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
// 4. 线程池不是正常运行或者添加到同步队列失败,尝试创建新的线程来执行任务
else if (!addWorker(command, false))
// 创建线程失败,执行拒绝策略
reject(command);
}
这个方法整体描述了线程池的工作机制,要注意的是,线程池的每个操作之前,都会先判断线程池的状态,如果在线程池的执行过程中用户关闭了线程池,线程池就不会再现阻塞队列中添加任务、或者是新建线程来处理任务。
ThreadPoolExecutor使用一个int类型的数字来存储线程池的状态,int变量中的前3位是线程池的状态,后29位是线程池中线程的数量。这个int类型的数字被放在一个原子类中。
线程池的状态枚举:
状态、容量相关的常量:
// 有效位数:29位,这里表示,一个int类型的数字,前3为存储状态,后29为存储线程数
private static final int COUNT_BITS = Integer.SIZE - 3; // Integer.SIZE是32,COUNT_BITS的值是29
/* 表示状态的常量,注意看二进制数的前三位 */
private static final int RUNNING = -1 << COUNT_BITS; // 11100000000000000000000000000000
private static final int SHUTDOWN = 0 << COUNT_BITS; // 00000000000000000000000000000000
private static final int STOP = 1 << COUNT_BITS; // 00100000000000000000000000000000
private static final int TIDYING = 2 << COUNT_BITS; // 01000000000000000000000000000000
private static final int TERMINATED = 3 << COUNT_BITS; // 01100000000000000000000000000000
// 容量:1左移29位,相当于1的29次方,1在二进制中移到第30位,然后再减1,得出的数字,在二进制中,除了前三位,后面的都是1
private static final int CAPACITY = (1 << COUNT_BITS) - 1; // 00011111111111111111111111111111
// ctlOf方法:两个int类型的数字按位或,遇1则1
private static int ctlOf(int rs, int wc) { return rs | wc; }
状态是如何计算的:
// 1、状态的初始化:线程池的状态和线程数被存储在AtomicInteger类型的实例中。
// RUNNING和0按位或,遇1则1,它是将RUNNING设置到存储状态和数目的变量中。
// 线程池实例一旦被创建,就是运行态
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
// 2、获取线程池的状态:参数c是AtomicInteger中存储的int类型的值,它和CAPACITY取反后的数进行按位与运算,遇0则0,
// CAPACITY取反后后29位变成0,前3为变成1,也就是保留参数c的前3位,这3位中存储的就是状态
private static int runStateOf(int c) { return c & ~CAPACITY; }
// 3、状态转换是怎么操作的?通过advanceRunState方法,参数targetState是状态常量,例如SHUTDOWN
private void advanceRunState(int targetState) {
// 循环操作,直到状态转换成功
for (;;) {
int c = ctl.get();
if (runStateAtLeast(c, targetState) ||
// 目标状态和线程数按位或,然后使用它的结果替换原来的状态,ctlOf是两个数字按位或,workerCountOf是计算线程数
ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
break;
}
}
线程数是如何计算的:
// 1、获取线程池中的线程数:参数c是AtomicInteger中存储的int类型的值,它和CAPACITY进行按位与运算,遇0则0,
// 因为CAPACITY的后29位都是1,前3位是0,所以是保留参数c的后29位,这29位中存储的就是线程数
private static int workerCountOf(int c) { return c & CAPACITY; }
// 2、线程数加1是怎么操作的:通过cas算法,直接在AtomicInteger中存储的int数上加1
private boolean compareAndIncrementWorkerCount(int expect) {
return ctl.compareAndSet(expect, expect + 1);
}
在之前的execute方法中,可以看到,添加线程并且执行任务是addWorker方法,在这里看一下addWorker方法和Worker类
addWorker方法:创建线程并且执行任务
private boolean addWorker(Runnable firstTask, boolean core) {
// 1. 这个循环是判断线程数,如果符合要求,线程数加1
retry:
for (;;) { // 自旋
int c = ctl.get();
// 判断线程池的运行状态
int rs = runStateOf(c);
// 没有必要创建新的worker的情况:线程池已关闭,或者线程池正在关闭 && 提交的任务是null && 阻塞队列中没有元素,
// 直接返回
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
for (;;) { // 自旋
// 计算工作线程的个数
int wc = workerCountOf(c);
// 如果大于最大线程数,return false
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
// 线程数加1
if (compareAndIncrementWorkerCount(c))
break retry;
// 如果设置失败,表示线程池状态有更新,重新获取状态,再次尝试
c = ctl.get(); // Re-read ctl
if (runStateOf(c) != rs)
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
}
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
// 创建worker实例,worker实例中封装了线程对象
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// Recheck while holding lock.
// Back out on ThreadFactory failure or if
// shut down before lock acquired.
// 再次检查线程池的运行状态
int rs = runStateOf(ctl.get());
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
// 将worker对象添加到集合中
workers.add(w);
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
workerAdded = true;
}
} finally {
mainLock.unlock();
}
if (workerAdded) {
// 开启worker对象中封装的线程
t.start();
workerStarted = true;
}
}
} finally {
// 如果创建线程失败
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
总结:addWorker方法做的事情
Worker类:ThreadPoolExecutor的成员内部类,继承了AbstractQueuedSynchronizer,这是juc中核心内容,实现了Runnable接口,
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable {
// 持有的线程实例
final Thread thread;
// 线程执行的第一个异步任务
Runnable firstTask;
// 线程执行了多少任务
volatile long completedTasks;
// 构造方法
Worker(Runnable firstTask) {
setState(-1); // 调用了AbstractQueuedSynchronizer中的方法
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this); // 调用线程工厂创建线程
}
// 线程启动后,会执行runWorker方法,同时传入当前实例
public void run() {
runWorker(this);
}
// 省略代码
}
// runWorker方法:获取传入worker实例中的task,如果task为null,则阻塞地获取队列中的task,执行task的run方法
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方法中,从阻塞队列中获取任务,如果获取不到异步任务,退出循环,执行finally中的方法,移除线程,
// 在getTask方法中完成线程数减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 {
// 执行任务的run方法
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); // 线程退出,将线程实例从线程池中移出
}
}
Worker负责执行任务,它持有线程对象,会从阻塞队列中阻塞地获取异步任务,然后执行任务的run方法。
Worker类继承了AQS,实现了自己的锁机制,它的锁是不可重入锁,作用是,当Worker正在执行任务时,会获取锁,执行完后,会释放锁,当用户执行了shutdown方法,打断每个线程时,会尝试获取每个Worker实例的锁,如果可以获取到,证明当前线程没有执行任务,然后打断线程。
打断空闲线程的代码:
private void interruptIdleWorkers(boolean onlyOne) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers) {
Thread t = w.thread;
if (!t.isInterrupted() && w.tryLock()) { // 尝试获取Worker实例的锁
try {
t.interrupt(); // 如果获取到,打断空闲线程
} catch (SecurityException ignore) {
} finally {
w.unlock();
}
}
if (onlyOne)
break;
}
} finally {
mainLock.unlock();
}
}
当执行shutdownNow方法时,则是只要线程启动,就打断
void interruptIfStarted() {
Thread t;
// getState() >= 0,表示无论有没有获取锁,都打断。
if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
}
}
}
负责创建线程,核心接口是ThreadFactory,创建线程的主要工作就是指定线程名称、优先级、线程组
// ThreadFactory:线程工厂的接口
public interface ThreadFactory {
// 创建线程的方法
Thread newThread(Runnable r);
}
// ThreadFactory的默认实现,这是Executors的静态内部类
static class DefaultThreadFactory implements ThreadFactory {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
// 线程组,默认使用当前线程的线程组
private final ThreadGroup group;
// 为线程编码,记录这是线程工厂创建的第几个线程
private final AtomicInteger threadNumber = new AtomicInteger(1);
// 线程名的前缀
private final String namePrefix;
DefaultThreadFactory() {
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup();
namePrefix = "pool-" +
poolNumber.getAndIncrement() +
"-thread-";
}
// 创建线程:主要是为新线程命名,同时继承父线程的线程组和优先级
public Thread newThread(Runnable r) {
Thread t = new Thread(group, r,
namePrefix + threadNumber.getAndIncrement(),
0);
if (t.isDaemon())
t.setDaemon(false);
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}
阻塞队列用于存放来不及执行的任务。
队列中定义的功能:
// Queue 队列的核心接口
public interface Queue<E> extends Collection<E> {
// 添加元素
boolean offer(E e);
// 移除元素
E poll();
// 查看队列的第一个元素
E peek();
}
// BlockQueue 阻塞队列,继承了Queue
public interface BlockingQueue<E> extends Queue<E> {
// 语义上,是阻塞地获取元素
E take() throws InterruptedException;
}
从队列中获取元素:之前runWorker中的getTask方法
private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?
for (;;) {
// 判断线程池状态
int c = ctl.get();
int rs = runStateOf(c);
// 判断状态:如果线程池状态是关闭,并且阻塞队列为空,
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount(); // 线程数减1
return null;
}
// 获取线程数
int wc = workerCountOf(c);
// 获取异步任务时是否要指定超时时间,如果当前线程数大于核心线程数,则需要计时
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
// 如果线程数超过最大线程数并且阻塞队列为空
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c)) // 线程数减1
return null;
continue;
}
try {
// 获取任务,会判断是否需要指定超时时长
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : // 指定阻塞时长,时长是线程存活时间
workQueue.take(); // 不指定阻塞时长,一直阻塞
if (r != null)
return r;
timedOut = true; // 超时
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
拒绝策略在代码设计上使用了策略模式,用户通过在创建线程池时传入不同类型的拒绝策略,可以控制线程池在无法执行异步任务时的行为。
// 核心接口:RejectedExecutionHandler
public interface RejectedExecutionHandler {
// 拒绝异步任务的执行
void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
}
// 默认实现:AbortPolicy 抛异常
public static class AbortPolicy implements RejectedExecutionHandler {
public AbortPolicy() { }
// 抛异常
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
}
}
shutdown方法:
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// java自带的安全检查工具,使用SecurityManage
checkShutdownAccess();
// 更改线程池的状态为SHUTDOWN
advanceRunState(SHUTDOWN);
// 所有的线程实例都调用interrupt方法
interruptIdleWorkers();
// 扩展点
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
mainLock.unlock();
}
// 尝试终止线程池
tryTerminate();
}
shutdownNow方法:
public List<Runnable> shutdownNow() {
List<Runnable> tasks;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// java自带的安全检查工具
checkShutdownAccess();
// 更改线程池的状态为STOP
advanceRunState(STOP);
// 所有的线程实例都调用interrupt方法
interruptWorkers();
// 将阻塞队列中的异步任务都抽取出来,返回给调用方
tasks = drainQueue();
} finally {
mainLock.unlock();
}
tryTerminate();
return tasks;
}
总结:shutdown和shutdownNow方法,都会调用interrupt方法,打断正在执行任务的线程,线程内部会把任务执行完再退出。不同点在于,shutdow方法会执行完阻塞队列中的任务,shutdownNow方法会把阻塞队列中的任务提取出来,返回给调用端,所以它是立刻关闭。