一,Java的Executor框架
图片引用自:https://img-blog.csdn.net/20160509161457055
1. Executor 接口
Executor 是一个用于提交 Runnable 任务。这个接口提供了一个将任务的提交从任务执行中解耦的方式,包含一些线程使用,调度等。
Executor 接口只定义了一个 execute 方法,用于执行 Runnable 任务。
package java.util.concurrent;
public interface Executor {
/**
* 提交在将来的某个时间执行给定的任务。任务可以在新的线程中执行,或者在线程池中,或者在调用者的线程,
* 这取决于具体的Executor的实现
*
* @param command Runnable 任务
* @throws RejectedExecutionException if this task cannot be
* accepted for execution
* @throws NullPointerException 如果任务为 null
*/
void execute(Runnable command);
}
Executor 经常用于替代显式地创建线程。例如使用如下代码替换常用的 new Thread(new(RunnableTask())).start()
Executor executor = <em>anExecutor</em>;
executor.execute(new RunnableTask1());
executor.execute(new RunnableTask2());
...
然而,Executor 接口并没有严格地要求任务进行异步执行。一个最简单的例子,executor 可以简单地在调用者的线程里立即运行提交的任务:
class DirectExecutor implements Executor {
public void execute(Runnable r) {
r.run();
}
}
更典型地,任务是在调用者所在线程之外的线程中执行。下面的 executor 为每一个任务单独开启了一个线程。
class ThreadPerTaskExecutor implements Executor {
public void execute(Runnable r) {
new Thread(r).start();
}
}
2. ExecutorService 接口
ExecutorService 继承自 Executor 接口,并提供了一些方法,用于管理终止 和提交任务并返回 Future 对象来跟踪异步任务的进展
package java.util.concurrent;
import java.util.List;
import java.util.Collection;
public interface ExecutorService extends Executor {
/**
* 开始有序地shutdown,这种情况下,之前已经提交的任务会继续执行,但新的任务会被拒绝。
*
* @throws SecurityException 如果存在security manager,如果shutdown的调用者没有 RuntimePermission 权限,则会抛出该异常
*/
void shutdown();
/**
* 尝试停止所有正在执行的任务,停止处理正在等待的任务,并返回正在等待执行的任务的列表
*
* 这个方法不等待正在执行的任务执行完成。使用 awaitTermination 来做这件事
*
* 无法保证能够停止正在执行的任务。典型的实现将通过 Thread#interrupt 来实现 cancel。对于无法响应 interrupt 的任务或者永远无法终止。
*
* @return 没有开始执行的任务列表
* @throws SecurityException 同shutdown
*/
List<Runnable> shutdownNow();
/**
* 如果 executor 已经被 shut down 则返回 true
*/
boolean isShutdown();
/**
* 如果所有任务已经在 shut down 之后执行完成,则返回 true。
* 注意:该方法只有在 shutdown 或者 shutdownNow 先被调用的情况下才有可能返回 true
*/
boolean isTerminated();
/**
* 在 shutdown 请求之后,阻塞,直到所有任务已经执行完成并进入 TERMINATED 状态,或者等待超时
*
* @param timeout 最大等待时间
* @param unit 参数 timeout 的单位,可取的值参照 TimeUnit 类
* @return {@code true} if this executor terminated and
* {@code false} if the timeout elapsed before termination
* @throws InterruptedException 等待的过程中如果被中断则抛出该异常
*/
boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException;
/**
* 提交一个有返回值的任务来执行,并返回一个 Future 对象来跟着任务执行情况。
* Future 的 get 方法会在执行完成时返回任务的结果。
*
* 如果想要立即阻塞来等待任务完成并返回结果,可以使用这种方式:
* {@code result = exec.submit(aCallable).get();}
*
* 注意:Exectors 类提供了一些用于将其它类型的对象转换成 Callabled 对象的方法,以便他们能够被提交。
*
* @param task 提交的任务
* @param <T> 任务的结果的类型
* @return Future 对象
* @throws RejectedExecutionException 如果当前任务无法被安排进行执行
* @throws NullPointerException 任务为 null
*/
<T> Future<T> submit(Callable<T> task);
/**
* 提交一个 Runnable 任务来执行,并返回一个 Future 对象表示那个任务.
*
* @param task the task to submit
* @param result the result to return
* @param <T> the type of the result
* @return a Future representing pending completion of the task
* @throws RejectedExecutionException if the task cannot be
* scheduled for execution
* @throws NullPointerException if the task is null
*/
<T> Future<T> submit(Runnable task, T result);
/**
* 和 submit(Runnable task, T result) 基本一致,只不过任务执行完成时 Future 的 get 方法返回 null
*/
Future<?> submit(Runnable task);
/**
* 执行给定的任务列表自,当所有任务完成时返回一个持有任务状态和结果的列表(列表每一个对象的 isDone 方法都返回 ture)
*
* 注意:任务完成可以是正常的执行完成或者由于抛出异常而被取消
*
* @param tasks 任务集合
* @param <T> 任务返回结果的类型
* @return 一个表示任务的 Futures 对象列表, 和给定的任务列表的 iterator 保持相同的顺序
* @throws InterruptedException 等待过程中遇到中断,这种情况下所有未完成的任务会被取消
* @throws NullPointerException 如果 tasks 为 null 或者任意一个元素为 null
* @throws RejectedExecutionException
*/
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
throws InterruptedException;
/**
* 基本上和 invokeAll(Collection<? extends Callable<T>> tasks) 一样,除了只会等待给定时间。
* 超过等待时间,还未完成的任务会被取消
*/
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException;
/**
* 执行给定的任务列表,只要有一个任务成功完成就返回这个任务的执行结果(不包含由于抛出异常而导致的执行完成). 方法返回时,未完成的任务会被取消
*
* @param tasks 任务集合
* @param <T> the type of the values returned from the tasks
* @return 任务执行结果
* @throws InterruptedException if interrupted while waiting
* @throws NullPointerException if tasks or any element task
* subject to execution is {@code null}
* @throws IllegalArgumentException if tasks is empty
* @throws ExecutionException 如果没有任务成功执行完成
* @throws RejectedExecutionException if tasks cannot be scheduled
* for execution
*/
<T> T invokeAny(Collection<? extends Callable<T>> tasks)
throws InterruptedException, ExecutionException;
/**
* 同 invokeAny(Collection<? extends Callable<T>> tasks),除了只会等待给定时间
*/
<T> T invokeAny(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
Future 相关内容可以参考:彻底理解Java的Future模式
3. AbstractExecutorService
AbstractExecutorService提供了 ExecutorService 的默认实现。实现了 submit, invokeAny 和 invokeAll 方法。
package java.util.concurrent;
import java.util.*;
public abstract class AbstractExecutorService implements ExecutorService {
// 将 Runnable 对象 和 Callable 对象封装成 RunnableFuture 对象,添加 Future 支持
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
return new FutureTask<T>(runnable, value);
}
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
return new FutureTask<T>(callable);
}
// 将将 Runnable 对象 和 Callable 对象封装成 Future 对象,并调用 execute 方法提交任务,返回 Future 对象
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
public <T> Future<T> submit(Runnable task, T result) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task, result);
execute(ftask);
return ftask;
}
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
/**
* invokeAny 的主要逻辑
*/
private <T> T doInvokeAny(Collection<? extends Callable<T>> tasks,
boolean timed, long nanos)
throws InterruptedException, ExecutionException, TimeoutException {
if (tasks == null)
throw new NullPointerException();
int ntasks = tasks.size();
if (ntasks == 0)
throw new IllegalArgumentException();
ArrayList<Future<T>> futures = new ArrayList<Future<T>>(ntasks);
// 使用 CompletionService 获取最早执行完成的任务
ExecutorCompletionService<T> ecs =
new ExecutorCompletionService<T>(this);
// For efficiency, especially in executors with limited
// parallelism, check to see if previously submitted tasks are
// done before submitting more of them. This interleaving
// plus the exception mechanics account for messiness of main
// loop.
try {
// Record exceptions so that if we fail to obtain any
// result, we can throw the last exception we got.
ExecutionException ee = null;
final long deadline = timed ? System.nanoTime() + nanos : 0L;
Iterator<? extends Callable<T>> it = tasks.iterator();
// Start one task for sure; the rest incrementally
futures.add(ecs.submit(it.next()));
--ntasks;
int active = 1;
for (;;) {
Future<T> f = ecs.poll();
if (f == null) {
if (ntasks > 0) {
--ntasks;
// 将任务提交到 CompletionService,并将返回的 Future 对象添加到列表中
futures.add(ecs.submit(it.next()));
++active;
}
else if (active == 0)
break;
else if (timed) {
// 等待给定时间,获取执行完成的任务
f = ecs.poll(nanos, TimeUnit.NANOSECONDS);
if (f == null)
throw new TimeoutException();
nanos = deadline - System.nanoTime();
}
else
f = ecs.take(); // 一直阻塞,直到有任务执行完成
}
if (f != null) {
// 如果有任务执行完成,则调用 Future 的 get 方法获取任务结果并返回
--active;
try {
return f.get();
} catch (ExecutionException eex) {
ee = eex;
} catch (RuntimeException rex) {
ee = new ExecutionException(rex);
}
}
}
if (ee == null)
ee = new ExecutionException();
throw ee;
} finally {
// 取消其它桑未完成的任务
for (int i = 0, size = futures.size(); i < size; i++)
futures.get(i).cancel(true);
}
}
public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
throws InterruptedException, ExecutionException {
try {
return doInvokeAny(tasks, false, 0);
} catch (TimeoutException cannotHappen) {
assert false;
return null;
}
}
public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
return doInvokeAny(tasks, true, unit.toNanos(timeout));
}
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
throws InterruptedException {
if (tasks == null)
throw new NullPointerException();
ArrayList<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
boolean done = false;
try {
for (Callable<T> t : tasks) {
RunnableFuture<T> f = newTaskFor(t);
futures.add(f);
execute(f);
}
// 循环阻塞来依次等待各个任务执行完成
for (int i = 0, size = futures.size(); i < size; i++) {
Future<T> f = futures.get(i);
if (!f.isDone()) {
try {
f.get();
} catch (CancellationException ignore) {
} catch (ExecutionException ignore) {
}
}
}
done = true;
return futures;
} finally {
// 如果任务执行过程中发生异常,则取消剩下的未执行完成的任务
if (!done)
for (int i = 0, size = futures.size(); i < size; i++)
futures.get(i).cancel(true);
}
}
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException {
if (tasks == null)
throw new NullPointerException();
long nanos = unit.toNanos(timeout);
ArrayList<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
boolean done = false;
try {
for (Callable<T> t : tasks)
futures.add(newTaskFor(t));
final long deadline = System.nanoTime() + nanos;
final int size = futures.size();
// Interleave time checks and calls to execute in case
// executor doesn't have any/much parallelism.
for (int i = 0; i < size; i++) {
execute((Runnable)futures.get(i));
nanos = deadline - System.nanoTime();
if (nanos <= 0L)
return futures;
}
for (int i = 0; i < size; i++) {
Future<T> f = futures.get(i);
if (!f.isDone()) {
if (nanos <= 0L)
return futures;
try {
f.get(nanos, TimeUnit.NANOSECONDS);
} catch (CancellationException ignore) {
} catch (ExecutionException ignore) {
} catch (TimeoutException toe) {
return futures;
}
nanos = deadline - System.nanoTime();
}
}
done = true;
return futures;
} finally {
if (!done)
for (int i = 0, size = futures.size(); i < size; i++)
futures.get(i).cancel(true);
}
}
}
4.ThreadPoolExecutor
ThreadPoolExecutor 继承自 AbstractExecutorService 类,用于实现线程池。
下面通过分析 ThreadPoolExecutor 的源码来了解它的工作原理。
4.1 线程池的运行状态
线程池有多个运行状态
- RUNNING: 接受新的任务和处理队列中的任务
- SHUTDOWN: 不接受新的任务,但是会处理队列中的任务
- STOP: 不接受新的任务,不处理队列中的任务,中断正在执行的任务
- TIDYING: 所有任务都以及终止,wokerkCount的值为0,过渡到TIDYING状态的线程将会运行 terminated()
- TERMINATED: terminated() 运行完成
线程池的生命周期中,状态的转移有以下几种情况:
- RUNNING -> SHUTDOWN : shutdown() 调用之后
- (RUNNING or SHUTDOWN) -> STOP : shutdownNow() 调用之后
- SHUTDOWN -> TIDYING : 当 queue 和 pool 都空了之后
- STOP -> TIDYING : 当 pool 空了之后
- TIDYING -> TERMINATED : 当 terminated() 执行完成之后
线程池的运行状态相关定义代码如下:
// 封装线程池的运行状态 runState 和 workerCount(有效的线程数量)
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
// runState 使用高三位,且按照从小到大的顺序,可以直接进行大小比较
private static final int RUNNING = -1 << COUNT_BITS;
private static final int SHUTDOWN = 0 << COUNT_BITS;
private static final int STOP = 1 << COUNT_BITS;
private static final int TIDYING = 2 << COUNT_BITS;
private static final int TERMINATED = 3 << COUNT_BITS;
// 包装/提取 ctl
// 获取线程的运行状态(低29位在 & 操作之后全是0,高3位取c得高三位)
private static int runStateOf(int c) { return c & ~CAPACITY; }
// 获取 workCount (低29位取c的低29位,高3位为0 )
private static int workerCountOf(int c) { return c & CAPACITY; }
// 根据 runState 和 workerCount 得到 ctl (异或操作,分别取 runState的高3位 和 workerCount 的低29位 )
private static int ctlOf(int rs, int wc) { return rs | wc; }
线程池的运行状态 runState 和 workerCount(有效的线程数量)是存放在同一个 atomic integer 变量 ctl中的。为了在同一个 int 中存放两个字段的信息,限制了 workerCount 的大小(使用int 32 位中的右边29位,因此最大值为 2^29 - 1),runState使用高3位。
因为是封装在变量 ctl 中,每次要获取线程池的运行状态 或者 workerCount,需要使用相应的方法(runStateOf 或 workerCountOf)对 ctl 进行解析。修改线程池运行状态 或者 workerCount 之后,要调用 ctlOf 将两个值打包,并设置到变量 crl 中。
4.2 线程池的一些其它属性
// 任务队列,存放任务并将任务转交给 worker 线程。使用 isEmpty() 判断队列是否为空
private final BlockingQueue<Runnable> workQueue;
// 用于控制对 workers 访问和相关的统计
private final ReentrantLock mainLock = new ReentrantLock();
// 存放线程池中所有的 worker 线程。在持有 mainLock 锁的情况下进行访问
private final HashSet<Worker> workers = new HashSet<Worker>();
// 用于支持 awaitTermination 的 wait 条件
private final Condition termination = mainLock.newCondition();
// 最大的并行存在的线程池大小
private int largestPoolSize;
// 完成的任务的数量。当 worker thread termination时才进行更新
private long completedTaskCount;
// Thread 工厂类。所有的线程通过这个工厂类创建(在 addWorker 方法中)
private volatile ThreadFactory threadFactory;
// 拒接执行处理器,用于线程池饱和 或者 shutdown 方法执行时拒接任务
private volatile RejectedExecutionHandler handler;
// 线程最大的空闲时间(单位:纳秒)。只有当线程数超过 corePoolSize 或者 allowCoreThreadTimeOut 为 true 时起作用。其它情况下空闲的线程会等待新的任务,而不会被回收
private volatile long keepAliveTime;
// core thread空闲时是否会超时的设置。如果为 false(默认值), 则当线程数不超过corePoolSize时,core thread空闲的时候仍保持村官哟状态;如果为 true,则当 core thread 空闲的时间超过 keepAliveTime 时会被中断
private volatile boolean allowCoreThreadTimeOut;
// 最小的保持存活的worker 数(不会超时)除非 allowCoreThreadTimeOut 为 true,这种情况下最小值为0
private volatile int corePoolSize;
// 最大的线程大小。以 CAPACITY 为界
private volatile int maximumPoolSize;
// 默认的 拒绝执行处理器,默认为 AbortPolicy,拒接时直接抛出 RejectedExecutionException 异常
private static final RejectedExecutionHandler defaultHandler =
new AbortPolicy();
// shutdown and shutdownNow 的调用者需要的权限
private static final RuntimePermission shutdownPerm =
new RuntimePermission("modifyThread");
4.3 创建线程池
虽然 ThreadPoolExecutor 提供了好几种形式的构造函数,不过最终调用的都是下面这构造函数
/**
* Creates a new {@code ThreadPoolExecutor} with the given initial
* parameters.
*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @param maximumPoolSize the maximum number of threads to allow in the
* pool
* @param keepAliveTime when the number of threads is greater than
* the core, this is the maximum time that excess idle threads
* will wait for new tasks before terminating.
* @param unit the time unit for the {@code keepAliveTime} argument
* @param workQueue the queue to use for holding tasks before they are
* executed. This queue will hold only the {@code Runnable}
* tasks submitted by the {@code execute} method.
* @param threadFactory the factory to use when the executor
* creates a new thread
* @param handler the handler to use when execution is blocked
* because the thread bounds and queue capacities are reached
* @throws IllegalArgumentException if one of the following holds:<br>
* {@code corePoolSize < 0}<br>
* {@code keepAliveTime < 0}<br>
* {@code maximumPoolSize <= 0}<br>
* {@code maximumPoolSize < corePoolSize}
* @throws NullPointerException if {@code workQueue}
* or {@code threadFactory} or {@code handler} is null
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
4.4 提交任务
// 提交任务。任务可能在新的线程中执行,或者在线程池中已有的线程中执行.
// 如果任务无法提交来执行 (线程池已经 shutdown 或者 已达到最大容量),使用 rejection executore handler 来处理
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
// 通过三步进行处理:
// 1. 如果当前正在运行的线程数少于 corePoolSize,创建一个新的线程来执行任务, command 作为第一个任务。如果线程添加成功,则结束
// 2. 如果线程池正在运行,并且能够成功将任务添加到等待队列 workQueue 中,则进行 double-check(可能存在终止的线程 或者线程池 shutdown),
根据需要回滚任务的入列操作并调用rejection execution handler 或者 开启一个新的线程 (不存在worker的情况下)
// 4. 尝试使用 maximumPoolSize 容量来添加 worker 开始新的线程执行任务。如果失败,则调用rejection execution handler处理
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);
}
其中调用的拒绝任务的相关代码如下:
/**
* 调用 rejection execution handler 来处理拒绝的任务
*/
final void reject(Runnable command) {
handler.rejectedExecution(command, this);
}
ThreadPoolExecutor 中定义了四种 rejection execution handler。默认使用的 AbortPolicy 策略。
// 如果线程池没有被 shutdown,直接在 execute 方法的执行线程里运行被拒绝的任务,并抛弃任务
public static class CallerRunsPolicy implements RejectedExecutionHandler {
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run();
}
}
}
// 直接抛出 RejectedExecutionException 异常
public static class AbortPolicy implements RejectedExecutionHandler {
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
}
}
// 直接抛弃给定的被拒绝的任务
public static class DiscardPolicy implements RejectedExecutionHandler {
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
}
}
// 如果线程池未被 shutdown,则抛弃等待最久的未处理的任务,并尝试重新提交任务
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
e.getQueue().poll();
e.execute(r);
}
}
}
4.5 添加 worker
// 尝试在当前的 pool 运行状态和给定的线程池大小限制的情况下添加 worker。
// 如果 worker 创建并且启动成功,则运行 firstTask 作为它的第一个任务。
// 如果 pool 已经 stop / pool shut down / thread factory 创建 thread 失败 / 线程执行过程中抛出异常 则方法返回 false
// @param core 用于控制是否使用 corePoolSize 作为线程池大小限制
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
for (;;) {
// 如果添加 worker 之前已经达到最大容量,则返回 false
int wc = workerCountOf(c);
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
// 如果 worker count 增加成功,则跳出最外层for循环,执行外层for循环后面的操作
if (compareAndIncrementWorkerCount(c))
break retry;
// 如果 run state 改变,则继续执行外层for循环
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
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
// 如果线程创建成功
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 获取锁期间重新检查 run state, 防止 ThreadFactory 报错 或者获取锁期间线程池 shut down
int rs = runStateOf(ctl.get());
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
// 将 worker 添加到集合,并增加最大持有worker数量
workers.add(w);
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
workerAdded = true;
}
} finally {
mainLock.unlock();
}
// 如果 worker 添加成功,则启动线程并设置 workerStarted 标志位 true
if (workerAdded) {
t.start();
workerStarted = true;
}
}
} finally {
// 如果线程创建失败 或者 线程启动失败,则回滚 worker thread 的创建
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
添加 worker 失败会调用 addWorkerFailed,代码如下:
// 回滚 worker thread 的创建
private void addWorkerFailed(Worker w) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 从 worker 集合中移除新增的worker,减少 worker count
if (w != null)
workers.remove(w);
decrementWorkerCount();
tryTerminate(); // 检查当前线程池是否满足 terminate 的条件,如果满足,则进行terminate(worker移除 或者 shutdown期间从队列中移除任务都要执行该操作)
} finally {
mainLock.unlock();
}
}
4.6 Worker 运行
/**
* worker 运行. 不断从队列中获取任务并执行
* @param w the worker
*/
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 {
// 执行 worker 相关的清理工作
processWorkerExit(w, completedAbruptly);
}
}
获取任务的代码如下:
// 执行阻塞或者等待指定的时间来获取任务
private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
// pool 停止 / pool shut down 且 任务队列为空,则减少worker数目并返回 null
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
int wc = workerCountOf(c);
// 当 allowCoreThreadTimeOut 为 true 或者 worker 数目大于 corePoolSize 时,只等待有限时间
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
// ( 如果 worker 数量大于 maximumPoolSize / 只等待有限时间 且已经超时 ) 并且 ( worker count 大于1 或者 work queue 是空的)
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
// 减少 worker 数目
if (compareAndDecrementWorkerCount(c))
return null;
// 如果减少 worker 数目失败 ,则并进入下一次循环 继续阐释获取任务
continue;
}
try {
// 等待指定时间 或者 一直阻塞
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
4.7 shutdown 操作
// shutdown - 之前已经提交的任务继续执行,不接受新的任务。
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 检查是否有 shutdown 权限
checkShutdownAccess();
// 将状态转换到SHUTDOWN状态
advanceRunState(SHUTDOWN);
// 中断空闲(当前没有持有锁)的线程
interruptIdleWorkers();
// 钩子,用于ScheduledThreadPoolExecutor执行一下清理操作
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
mainLock.unlock();
}
tryTerminate();
}
// 尝试停止所有正在执行的任务,停止等待处理等待的任务,返回正在等待执行的任务的列表
// 不能保证一定能停止正在执行任务的线程(有些任务可能无法响应 interrupt , 这种情况下无法终止)
public List<Runnable> shutdownNow() {
List<Runnable> tasks;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
// 尝试转移到 STOP 状态
advanceRunState(STOP);
interruptWorkers();
// 将任务队列中正在等待的任务全部移除并放入列表中,用于返回
tasks = drainQueue();
} finally {
mainLock.unlock();
}
// 尝试中断线程池
tryTerminate();
return tasks;
}
5. ScheduledThreadPoolExecutor
ScheduledThreadPoolExecutor 继承自 ThreadPoolExecutor,实现了 ScheduledExecutorService 接口。
public class ScheduledThreadPoolExecutor
extends ThreadPoolExecutor
implements ScheduledExecutorService {
// ...
}
ScheduledExecutorService 接口继承自 ExecutorService 接口,定义了一些定时任务执行的方法, 用于在给定的延迟之后 或者周期性地执行 run 方法。
package java.util.concurrent;
public interface ScheduledExecutorService extends ExecutorService {
/**
* 创建和执行给定的延迟之后只执行一次的操作。返回一个 ScheduledFuture 对象
*
* @param command 待执行的任务
* @param delay the time from now to delay execution
* @param unit the time unit of the delay parameter
* @return a ScheduledFuture representing pending completion of
* the task and whose {@code get()} method will return
* {@code null} upon completion
* @throws RejectedExecutionException if the task cannot be
* scheduled for execution
* @throws NullPointerException if command is null
*/
public ScheduledFuture<?> schedule(Runnable command,
long delay, TimeUnit unit);
// 同上
public <V> ScheduledFuture<V> schedule(Callable<V> callable,
long delay, TimeUnit unit);
/**
* Creates and executes a periodic action that becomes enabled first
* after the given initial delay, and subsequently with the given
* period; that is executions will commence after
* {@code initialDelay} then {@code initialDelay+period}, then
* {@code initialDelay + 2 * period}, and so on.
* If any execution of the task
* encounters an exception, subsequent executions are suppressed.
* Otherwise, the task will only terminate via cancellation or
* termination of the executor. If any execution of this task
* takes longer than its period, then subsequent executions
* may start late, but will not concurrently execute.
*
* @param command the task to execute
* @param initialDelay the time to delay first execution
* @param period the period between successive executions
* @param unit the time unit of the initialDelay and period parameters
* @return a ScheduledFuture representing pending completion of
* the task, and whose {@code get()} method will throw an
* exception upon cancellation
*/
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
long initialDelay,
long period,
TimeUnit unit);
// 在初始延迟之后,每隔给定延迟(上一次任务执行完成到下一次任务开始执行之间的间隔)执行一次任务
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
long initialDelay,
long delay,
TimeUnit unit);
}
这里的 ScheduleFuture 接口继承自 Delayed 和 Future。
/**
* A delayed result-bearing action that can be cancelled.
* Usually a scheduled future is the result of scheduling
* a task with a {@link ScheduledExecutorService}.
*
* @since 1.5
* @author Doug Lea
* @param <V> The result type returned by this Future
*/
public interface ScheduledFuture<V> extends Delayed, Future<V> {
}
5.1 构造函数
/**
* Creates a new ScheduledThreadPoolExecutor with the given
* initial parameters.
*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @param threadFactory the factory to use when the executor
* creates a new thread
* @param handler the handler to use when execution is blocked
* because the thread bounds and queue capacities are reached
* @throws IllegalArgumentException if {@code corePoolSize < 0}
* @throws NullPointerException if {@code threadFactory} or
* {@code handler} is null
*/
public ScheduledThreadPoolExecutor(int corePoolSize,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue(), threadFactory, handler);
}
ScheduledThreadPoolExecutor 中定义了一个 DelayedWorkQueue 阻塞队列,基于最小堆实现,实现上与 PriorityQueue 差不多。
只不过 DelayedWorkQueue 只接受 RunnableScheduledFuture 对象。RunnableScheduledFuture 记录了元素在堆中的索引(可以看一下实现类 ScheduledFutureTask),可以用来进行一些优化(任务取消时寻找任务,加速任务的移除等等。)
5.2 任务提交
ScheduledThreadPoolExecutor 提供了多种任务执行方式,如 给定延迟之后执行一次 (schedule 和 execute),给定延迟之后以固定的频率执行(scheduleAtFixedRate),给定延迟之后以固定的延迟执行(scheduleWithFixedDelay)。
// 在给定的延迟之后执行一次任务
public ScheduledFuture<?> schedule(Runnable command,
long delay,
TimeUnit unit) {
if (command == null || unit == null)
throw new NullPointerException();
// 将 Runnable 对象封装成 RunnableScheduledFuture 对象
RunnableScheduledFuture<?> t = decorateTask(command,
new ScheduledFutureTask<Void>(command, null,
triggerTime(delay, unit)));
// 将任务添加到任务队列并执行
delayedExecute(t);
return t;
}
// 在给定的延迟之后,以固定的频率(每隔给定时间)执行任务
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
long initialDelay,
long period,
TimeUnit unit) {
if (command == null || unit == null)
throw new NullPointerException();
if (period <= 0)
throw new IllegalArgumentException();
ScheduledFutureTask<Void> sft =
new ScheduledFutureTask<Void>(command,
null,
triggerTime(initialDelay, unit),
unit.toNanos(period));
RunnableScheduledFuture<Void> t = decorateTask(command, sft);
sft.outerTask = t;
delayedExecute(t);
return t;
}
// 在给定延迟之后,以固定延迟周期性执行任务
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
long initialDelay,
long delay,
TimeUnit unit) {
if (command == null || unit == null)
throw new NullPointerException();
if (delay <= 0)
throw new IllegalArgumentException();
ScheduledFutureTask<Void> sft =
new ScheduledFutureTask<Void>(command,
null,
triggerTime(initialDelay, unit),
unit.toNanos(-delay));
RunnableScheduledFuture<Void> t = decorateTask(command, sft);
sft.outerTask = t;
delayedExecute(t);
return t;
}
// 立即执行任务(只执行一次,非周期性)
public void execute(Runnable command) {
schedule(command, 0, NANOSECONDS);
}
其中 delayedExecute 相关逻辑如下:
private void delayedExecute(RunnableScheduledFuture<?> task) {
// 如果线程池已经 shutdown,拒绝任务
if (isShutdown())
reject(task);
else {
// 将任务添加到队列
super.getQueue().add(task);
// 再次检查任务是否能够运行(防止任务添加到队列之后线程池被 shutdown)。如果不行,从队列中移除任务并取消任务
if (isShutdown() &&
!canRunInCurrentRunState(task.isPeriodic()) &&
remove(task))
task.cancel(false);
else
// 确保至少有一个 worker,可以开始执行任务
ensurePrestart();
}
}
下面介绍一下 ScheduledThreadPoolExecutor 中用到的任务实体类。
private class ScheduledFutureTask<V>
extends FutureTask<V> implements RunnableScheduledFuture<V> {
/** Sequence number to break ties FIFO */
private final long sequenceNumber;
// 任务的执行时间,单位纳秒
private long time;
// 重复执行任务的周期。正数表示是 fixed-rate 执行;负数表示是 fixed-delay 执行;
// 0 表示是一次性任务
private final long period;
/** reExecutePeriodic 中重新入队列的任务 */
RunnableScheduledFuture<V> outerTask = this;
// 任务在堆(使用数组实现)中的索引,用于执行更快的取消,移除等
int heapIndex;
// 创建一个一次性的任务
ScheduledFutureTask(Runnable r, V result, long ns) {
super(r, result);
this.time = ns;
this.period = 0;
this.sequenceNumber = sequencer.getAndIncrement();
}
// 创建一个周期性执行的任务
ScheduledFutureTask(Runnable r, V result, long ns, long period) {
super(r, result);
this.time = ns;
this.period = period;
this.sequenceNumber = sequencer.getAndIncrement();
}
// 创建一个一次性的任务
ScheduledFutureTask(Callable<V> callable, long ns) {
super(callable);
this.time = ns;
this.period = 0;
this.sequenceNumber = sequencer.getAndIncrement();
}
// 实现 Delayed 接口的 getDelay 方法
public long getDelay(TimeUnit unit) {
return unit.convert(time - now(), NANOSECONDS);
}
// 用于堆中元素的放置,根据等待时间由小到大排序
public int compareTo(Delayed other) {
if (other == this) // compare zero if same object
return 0;
if (other instanceof ScheduledFutureTask) {
ScheduledFutureTask<?> x = (ScheduledFutureTask<?>)other;
long diff = time - x.time;
if (diff < 0)
return -1;
else if (diff > 0)
return 1;
else if (sequenceNumber < x.sequenceNumber)
return -1;
else
return 1;
}
long diff = getDelay(NANOSECONDS) - other.getDelay(NANOSECONDS);
return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;
}
// 返回 true 如果当前任务是周期性任务
public boolean isPeriodic() {
return period != 0;
}
//为周期性任务设置下一次运行时间
private void setNextRunTime() {
long p = period;
if (p > 0)
time += p;
else
time = triggerTime(-p);
}
public boolean cancel(boolean mayInterruptIfRunning) {
boolean cancelled = super.cancel(mayInterruptIfRunning);
if (cancelled && removeOnCancel && heapIndex >= 0)
remove(this);
return cancelled;
}
// 覆盖 FutureTask 的版本,来进行周期性任务的状态重置/重新入队列
public void run() {
boolean periodic = isPeriodic();
// 如果在当前运行状态下无法运行任务,则取消任务
if (!canRunInCurrentRunState(periodic))
cancel(false);
else if (!periodic)
// 如果是非周期性任务则执行调用任务的 run 方法
ScheduledFutureTask.super.run();
// 调用任务的 run 方法并重置任务的状态为初始状态
else if (ScheduledFutureTask.super.runAndReset()) {
// 设置任务的下一次允许时间
setNextRunTime();
// 尝试将任务重新添加到任务队列中
reExecutePeriodic(outerTask);
}
}
}
reExecutePeriodic 的逻辑如下:
/**
* 在线程池当前运行状态运行的情况下将一个周期性任务重新添加到队列中。
*
* @param task the task
*/
void reExecutePeriodic(RunnableScheduledFuture<?> task) {
if (canRunInCurrentRunState(true)) {
super.getQueue().add(task);
if (!canRunInCurrentRunState(true) && remove(task))
task.cancel(false);
else
ensurePrestart();
}
}
下一篇文章将介绍 Executors 类中的相关方法的使用。