Future、ExecutorService源码解析
Runnable创建的是没有返回值的线程,同时还可以创建有返回值的线程。
1.整体架构
线程API之间的关系如下图,
通过下面的代码对各个API的使用做演示,
// 创建一个线程池(实际开发时线程池不是这样创建的,这里只是演示)
ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 3, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>());
// futureTask构造器的入参是 Callable
FutureTask futureTask = new FutureTask(new Callable<String> () {
@Override
public String call() throws Exception {
Thread.sleep(3000);
return "我是子线程"+Thread.currentThread().getName();
}
});
// 把任务提交到线程池中,线程池会分配线程执行任务
executor.submit(futureTask);
// 得到任务执行的结果
String result = (String) futureTask.get();
log.info("result is {}",result);
- Callable:定义需要执行的任务,可以有返回值
- FutureTask:线程任务,入参是Callable,是对Callable的包装,方便线程池的使用。通过
FutureTask.get
方法获取子线程计算结果
2.Callable接口
Callable接口定义了线程执行任务的代码,与Runnable的作用相同,区别是Callable有返回值。接口的定义如下,
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}
返回值是泛型,使用时不会直接使用Callable,而是会结合FutureTask一起使用。
3.FutureTask类
FutureTask是线程的具体执行,该类实现了RunnableFuture接口。RunnableFuture接口是Runnable和Future接口的子接口。通过这一个继承关系逐一进行说明。
Future接口
Callable接口可以返回子线程执行结果,而Future接口用于获取Callable接口实现类的返回结果。
Future接口的类注释,
- Future定义了异步计算。接口的方法用于检查计算是否完成,等待计算完成,并取回计算结果等方法
- 使用 get方法可以得到结果,该方法会一直阻塞到子线程任务完成才返回
- cancel 方法可以取消任务
// 如果任务执行成功或已被取消,则无法再取消的,直接返回true
// 如果任务还没被进行时,发起取消,可以取消成功的。
// 如果取消时,任务已经在运行了,mayInterruptIfRunning 为 true 的话,就可以打断运行中的线程;反之,表示不能打断直接返回
boolean cancel(boolean mayInterruptIfRunning);
// 返回线程是否已经被取消了,true 表示已经被取消了
// 如果线程已经运行结束了,isCancelled 和 isDone 返回的都是 true
boolean isCancelled();
// 线程是否已经运行结束了
boolean isDone();
// 等待结果返回
// 如果任务被取消了,抛 CancellationException 异常
// 如果等待过程中被打断了,抛 InterruptedException 异常
V get() throws InterruptedException, ExecutionException;
// 等待,但是带有超时时间的,如果超时时间外仍然没有响应,抛 TimeoutException 异常
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
Future接口定义了各种对任务进行管理的方法。
RunnableFuture接口
RunnableFuture也是一个接口,
public interface RunnableFuture<V> extends Runnable, Future<V> {
/**
* Sets this Future to the result of its computation
* unless it has been cancelled.
*/
void run();
}
RunnableFuture接口的目的是将Runnable和Future进行整合,让Future对Runnable进行管理。
统一Callable和Runnable
之前对任务的创建方式进行了拓展,
- 无返回值的 Runnable
- 有返回值的 Callable
两种接口的定义使得任务的创建方式并不统一,所以在 FutureTask类实现了RunnableFuture接口,同时集合了Callable接口(因为 Callable是FutureTask的属性),还提供了两者的转化方法。
1)FutureTask类定义
public class FutureTask<V> implements RunnableFuture<V> {}
从类定义上可以看出来 FutureTask 实现了 RunnableFuture 接口,即间接实现了 Runnnable 接口,故FutureTask 本身就是个 Runnnable。同时 FutureTask 也实现了 Future,也就是说 FutureTask 具备对任务进行管理的功能。
2)FutureTask类属性
// 任务状态
private volatile int state;
private static final int NEW = 0;//线程任务创建
private static final int COMPLETING = 1;//任务执行中
private static final int NORMAL = 2;//任务执行结束
private static final int EXCEPTIONAL = 3;//任务异常
private static final int CANCELLED = 4;//任务取消成功
private static final int INTERRUPTING = 5;//任务正在被打断中
private static final int INTERRUPTED = 6;//任务被打断成功
// 组合了 Callable
private Callable<V> callable;
// 异步线程返回的结果
private Object outcome;
// 当前任务所运行的线程
private volatile Thread runner;
// 记录调用 get 方法时被等待的线程
private volatile WaitNode waiters;
Callable是FutureTask的属性,这使得 FutureTask具备了将Runnable转化为Callable的前提。
3)FutureTask构造器
FutureTask类有两个构造器,分别接收 Callable和Runnable作为参数,
// 使用 Callable 进行初始化
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
// 任务状态初始化
this.state = NEW; // ensure visibility of callable
}
// 使用 Runnable 初始化,并传入result 作为返回结果。
// Runnable 是没有返回值的,所以 result 一般设置为null
public FutureTask(Runnable runnable, V result) {
// Executors.callable 方法把Runnable适配成RunnableAdapter,RunnableAdapter实现了Callable
// 所以也就是把 runnable 直接适配成了 callable。
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}
FutureTask的两个构造器最终的目的是将入参都转化为Callable。
4)Runnable适配Callable
当FutureTask的构造方法传入的参数为Runnable类型,会使用Executors类的callable方法将 Runnable转化为 Callable。因为Runnable和Callable都是接口,无法直接转化,所以此处引入一个RunnableAdapter类进行转化。该类是Executors类的静态内部类,相当于一个适配器,将Runnable适配为Callable。
Executors类是一个工厂类,callable
方法创建一个 RunnableAdapter对象并返回,
public static <T> Callable<T> callable(Runnable task, T result) {
if (task == null)
throw new NullPointerException();
return new RunnableAdapter<T>(task, result);
}
RunnableAdapter类中对 Runnable的适配方式很简单,
static final class RunnableAdapter<T> implements Callable<T> {
final Runnable task;
final T result;
RunnableAdapter(Runnable task, T result) {
this.task = task;
this.result = result;
}
public T call() {
task.run();
return result;
}
}
- RunnableAdapter实现了Callable接口,所以该类本身就是任务类
- Runnable是RunnableAdapter的一个属性,在RunnableAdapter复写的 Callable的
call
方法中,调用了Runnable的run
方法。
FutureTask对任务的管理
Future接口对任务的管理定义了一系列方法,FutureTask是Future接口的子类,所以FutureTask对任务管理方法进行了复写。几个较为关键的方法进行说明,
1)get方法
get方法有无限阻塞和设置超时时间两种,一般使用设置超时时间的方法,
public V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
if (unit == null)
throw new NullPointerException();
int s = state;
if (s <= COMPLETING &&
(s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING)
throw new TimeoutException();
return report(s);
}
对几处代码进行说明,
// 任务正在被执行,且等待一定的时间后,仍然在执行中,直接抛出异常
(s <= COMPLETING && (s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING)
awaitDone方法源码如下,
/**
* 返回线程任务执行结果,完成、中断或超时
* @param timed true if use timed waits
* @param nanos time to wait, if timed
* @return state upon completion
*/
private int awaitDone(boolean timed, long nanos)
throws InterruptedException {
final long deadline = timed ? System.nanoTime() + nanos : 0L;
WaitNode q = null;
boolean queued = false; // 不排队
for (;;) {
if (Thread.interrupted()) { // 如果线程已被打断,删除抛出异常
removeWaiter(q);
throw new InterruptedException();
}
int s = state;
if (s > COMPLETING) { // 任务已经执行结束(完成、取消或打断),返回任务状态s
if (q != null) // q是WaitNode对象(FutureTask的内部类),用于记录等待线程
q.thread = null; // WaitNode的thread属性指向当前线程,线程执行完成后将该线程置空
return s;
}
else if (s == COMPLETING) // 如果任务正在执行且未超时,当前线程让出cpu使用权,重新竞争
Thread.yield();
else if (q == null)
q = new WaitNode(); // 第一次运行时新建 WaitNode,当前线程就是WaitNode对象的thread属性
else if (!queued) // 第一次都会执行这里,执行成功之后,queued为true,不会再执行。新建的WaitNode对象当做waiters链表的第一个元素
queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
q.next = waiters, q);
// 任务既没有被运行也没有结束,对应NEW状态
else if (timed) { // 如果设置超时
nanos = deadline - System.nanoTime();
if (nanos <= 0L) { // 已经超时,从链表中删除当前WaitNode节点
removeWaiter(q);
return state;
}
LockSupport.parkNanos(this, nanos); // 还未超时则进入TIMED_WAITING状态
}
else // 未设置超时,进入WAITING状态
LockSupport.park(this);
}
}
get 方法中做了很多 wait 的事情,当发现任务还在进行中,没有完成时,就会阻塞当前进程,等待任务完成后再返回结果值。阻塞底层使用的是 LockSupport.park 方法,使当前线程进入 WAITING 或 TIMED_WAITING 状态。
2)run方法
public void run() {
// 任务不是新建的或者当前任务正在被执行,直接返回
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
// Callable不为空,该任务创建成功且未被执行,状态为NEW
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call(); // 执行任务
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
set(result); // 给返回值
}
} finally {
runner = null;
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
在执行 c.call()
代码时,
- 如果入参是 Runnable 的话, 调用路径为
c.call() -> RunnableAdapter.call() -> Runnable.run()
- 如果入参是 Callable 的话,直接调用Callable的
call
方法
3)cancel方法
public boolean cancel(boolean mayInterruptIfRunning) {
if (!(state == NEW && //任务状态不是创建 并且不能把 new 状态置为取消,直接返回 false
UNSAFE.compareAndSwapInt(this, stateOffset, NEW,
mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
return false;
// 进行取消操作,打断可能会抛出异常
try {
if (mayInterruptIfRunning) { // mayInterruptIfRunning 为 true 的话,就可以打断运行中的线程
try {
Thread t = runner;
if (t != null)
t.interrupt();
} finally {
//状态设置成已打断
UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
}
}
} finally {
// 清理线程
finishCompletion();
}
return true;
}
总结
FutureTask是关键,通过 FutureTask 把 Runnnable、Callable、Future 都串起来了,使 FutureTask 具有三者的功能,统一了 Runnnable 和 Callable。