在 Java 中一般通过继承 Thread 类或者实现 Runnable 接口这两种方式来创建多线程,但是这两种方式都有个缺陷,就是不能在执行完成后获取执行的结果,因此Java 1.5 之后提供了 Callable 和 Future 接口,通过它们就可以在任务执行完毕之后得到任务的执行结果。
Future Demo
interface ArchiveSearcher { String search(String target); }
class App {
ExecutorService executor = ...
ArchiveSearcher searcher = ...
void showSearch(final String target)
throws InterruptedException {
Future<String> future = executor.submit(new Callable<String>() {
public String call() {
return searcher.search(target);
}});
displayOtherThings(); // do other things while searching
try {
displayText(future.get()); // use future
} catch (ExecutionException ex) { cleanup(); return; }
}
}}
FutureTask 是一个支持取消行为的异步任务执行器。该类实现了 Future 接口的方法:
- 取消任务执行。
- 查询任务是否执行完成。
- 获取任务执行结果(get 任务必须得执行完成才能获取结果,否则会阻塞直至任务完成)。
FutureTask Demo
FutureTask<String> future = new FutureTask<String>(new Callable<String>() {
public String call() {
return searcher.search(target);
}});
executor.execute(future);
}
继承关系
FutureTask 实现了 RunnableFuture 接口, RunnableFuture 接口继承了 Runnable、Future 接口。
Future 接口
public interface Future<V> {
/**
* 取消任务
*
* @param mayInterruptIfRunning 是否允许取消正在执行却没有执行完毕的任务
* @return true-取消任务成功,false-取消任务失败
*/
boolean cancel(boolean mayInterruptIfRunning);
/**
* 任务是否被取消成功
*/
boolean isCancelled();
/**
* 任务是否已经完成
*/
boolean isDone();
/**
* 获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回
*/
V get() throws InterruptedException, ExecutionException;
/**
* 获取执行结果,如果在指定时间内,还没获取到结果,就直接返回 null
*/
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
内部任务运行状态属性
state 可能存在的状态转换
- NEW -> COMPLETING -> NORMAL(有正常结果)
- NEW -> COMPLETING -> EXCEPTIONAL(执行过程中出现异常的流程,结果为异常)
- NEW -> CANCELLED(被取消,无结果)
- NEW -> INTERRUPTING -> INTERRUPTED(被中断,无结果)
private volatile int state;
private static final int NEW = 0; // 表示这是一个新的任务,或者还没有执行完的任务,初始状态
private static final int COMPLETING = 1; // 表示任务执行结束(正常执行结束,或者发生异常结束),但是还没有将结果保存到 outcome 中。中间状态
private static final int NORMAL = 2; // 表示任务正常执行结束,并且已经把执行结果保存到 outcome 字段中。最终状态
private static final int EXCEPTIONAL = 3; // 表示任务发生异常结束,异常信息已经保存到 outcome 中。最终状态。
private static final int CANCELLED = 4; // 任务执行结束之前被取消了,但是不要求中断正在执行的线程,也就是调用了 cancel(false)。最终状态
private static final int INTERRUPTING = 5; // 任务在新建之后,执行结束之前被取消了,并要求中断线程的执行,也就是调用了 cancel(true),这时任务状态就是 INTERRUPTING。中间状态。
private static final int INTERRUPTED = 6; // 调用 cancel(true) 取消异步任务,会调用 interrupt() 中断线程的执行,然后状态会从 INTERRUPTING 变到 INTERRUPTED。最终状态。
其他属性
/**
* 将要执行的任务
*/
private Callable<V> callable;
/**
* 用来保存计算任务的返回结果,或者执行过程中抛出的异常
*/
private Object outcome;
/**
* 执行任务的执行线程
*/
private volatile Thread runner;
/**
* 等待节点,如果任务还没有执行结束,那么调用 get() 获取结果的线程会阻塞,在这个阻塞队列中排队等待
*/
private volatile WaitNode waiters;
内部节点
等待节点,栈结构的等待队列
static final class WaitNode {
volatile Thread thread;
volatile WaitNode next;
WaitNode() {
thread = Thread.currentThread();
}
}
构造方法
允许传入 Callable、Runnable 类型
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // 新任务状态
}
/**
* 将 Runnabl 转化为 Callable,这里使用了适配器模式实现
*/
public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
this.state = NEW; // 新任务状态
}
任务执行:run()
FutureTask 封装了计算任务,无论是提交给 Thread 执行,或者线程池执行,调用的都是 FutureTask.run()
。
run() 执行一个任务,会被线程自动调用执行。
public void run() {
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
// state !=NEW,说明任务已经被其他线程执行,甚至执行结束,或者被取消了,直接返回
// 判断执行任务的线程对象 runner 是否为空,为空就将当前执行线程赋值给 runner 属性,不为空说明已经有线程准备执行这个任务了
return;
try {
Callable<V> c = callable;
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);
}
}
/**
* 设置任务执行成功状态,最终状态 NORMAL
*/
protected void set(V v) {
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
outcome = v;
UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
finishCompletion();
}
}
/**
* 设置任务执行异常,最终状态 EXCEPTIONAL
*/
protected void setException(Throwable t) {
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
outcome = t;
UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
finishCompletion();
}
}
/**
* 判断是否在执行的过程中被中断了,如果被中断,处理中断
*/
private void handlePossibleCancellationInterrupt(int s) {
if (s == INTERRUPTING)
while (state == INTERRUPTING)
// 表示正在被中断,让出线程的执行权,给其他线程来执行
Thread.yield();
// assert state == INTERRUPTED;
// We want to clear any interrupt we may have received from
// cancel(true). However, it is permissible to use interrupts
// as an independent mechanism for a task to communicate with
// its caller, and there is no way to clear only the
// cancellation interrupt.
//
// Thread.interrupted();
}
/**
* 在任务执行完成(包括取消、正常结束、发生异常),将等待线程列表唤醒
**/
private void finishCompletion() {
// assert state > COMPLETING;
for (WaitNode q; (q = waiters) != null; ) {
if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
for (; ; ) {
Thread t = q.thread;
if (t != null) {
q.thread = null;
// 唤醒节点
LockSupport.unpark(t);
}
WaitNode next = q.next;
if (next == null)
break;
q.next = null; // unlink to help gc
q = next;
}
break;
}
}
done(); // 这里可以自定义实现任务完成后要做的事(在子类中重写 done() 方法)
// 任务执行完,释放资源
callable = null;
}
/**
* 这个方法什么都没有做,不过子类可以实现这个方法,做一些额外的操作
*/
protected void done() {
}
runAndReset() 任务可被多次执行, 这个方法同 run() 方法的区别在于这个方法不会设置任务的执行结果值,而只是执行任务完之后,将任务的状态重新设置为初始化的可被执行状态。
protected boolean runAndReset() {
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return false;
boolean ran = false;
int s = state;
try {
Callable<V> c = callable;
if (c != null && s == NEW) {
try {
c.call(); // don't set result
ran = true;
} catch (Throwable ex) {
setException(ex);
}
}
} finally {
runner = null;
s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
return ran && s == NEW;
}
任务取消:cancel()
当调用 cancel 方法被调用时:如果任务还没有执行,那么这个任务就不会执行了;如果任务已经执行,且 mayInterruptIfRunning=true,那么执行任务的线程会被中断。
public boolean cancel(boolean mayInterruptIfRunning) {
if (!(state == NEW &&
UNSAFE.compareAndSwapInt(this, stateOffset, NEW,
mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))
// state !=NEW,说明任务已经结束或者被取消了
// state ==NEW,mayInterruptIfRunning=true,说明要中断任务的执行,NEW->INTERRUPTING,mayInterruptIfRunning=false,不需要中断,状态改为CANCELLED
return false;
try {
if (mayInterruptIfRunning) {
try {
// 读取当前正在执行任务的线程 runner 并中断
Thread t = runner;
if (t != null)
t.interrupt();
} finally {
// 修改状态为 INTERRUPTED
UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
}
}
} finally {
finishCompletion();
}
return true;
}
结果返回:get()
获取任务结果,如果这个任务还没有执行结束并且未设置超时,则调用线程会进入阻塞状态。
public V get() throws InterruptedException, ExecutionException {
int s = state;
// state <= COMPLETING,说明任务还没开始执行或还未执行完成,调用 awaitDone() 阻塞该调用线程
if (s <= COMPLETING)
s = awaitDone(false, 0L);
return report(s);
}
/**
* 返回任务结果或任务异常
* <p>
* 读取 outcome,将 state 映射到最后返回的结果中
* s == NORMAL 说明任务正常结束,返回正常结果,s >= CANCELLED 抛出 CancellationException
*/
@SuppressWarnings("unchecked")
private V report(int s) throws ExecutionException {
Object x = outcome;
if (s == NORMAL)
return (V) x;
if (s >= CANCELLED)
throw new CancellationException();
throw new ExecutionException((Throwable) x);
}
/**
* 阻塞等待
*/
private int awaitDone(boolean timed, long nanos)
throws InterruptedException {
final long deadline = timed ? System.nanoTime() + nanos : 0L;
WaitNode q = null;
boolean queued = false;
for (; ; ) {
// 1. 如果该线程执行 interrupt() 方法,则从队列中移除该节点,并抛出异常
if (Thread.interrupted()) {
removeWaiter(q);
throw new InterruptedException();
}
int s = state;
if (s > COMPLETING) {
// 2. 任务执行完成或取消,返回完成状态
if (q != null)
q.thread = null;
return s;
} else if (s == COMPLETING)
// 3. 说明正在 set 结果,此时让线程稍等一下
Thread.yield();
else if (q == null)
// 构造一个等待节点 WaitNode
q = new WaitNode();
else if (!queued)
// 4. 将当前线程加入到 FutureTask 的等待线程队列首节点中去
queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
q.next = waiters, q);
else if (timed) {
// 设置超时后,如果超时,则移除等待队列中对应节点并返回对应的状态,并返回状态
nanos = deadline - System.nanoTime();
if (nanos <= 0L) {
removeWaiter(q);
return state;
}
// 指定等待时间
LockSupport.parkNanos(this, nanos);
} else
// 等待
LockSupport.park(this);
}
}
/**
* 移除等待队列节点
*/
private void removeWaiter(WaitNode node) {
if (node != null) {
node.thread = null;
retry:
for (; ; ) { // restart on removeWaiter race
for (WaitNode pred = null, q = waiters, s; q != null; q = s) {
s = q.next;
if (q.thread != null)
pred = q;
else if (pred != null) {
pred.next = s;
if (pred.thread == null) // check for race
continue retry;
} else if (!UNSAFE.compareAndSwapObject(this, waitersOffset,
q, s))
continue retry;
}
break;
}
}
}
/**
* 指定超时,超时之后会抛出 TimeoutException
*/
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);
}
任务状态方法
/**
* 返回是否被取消
*/
public boolean isCancelled() {
return state >= CANCELLED;
}
/**
* 返回是否执行完成
*/
public boolean isDone() {
return state != NEW;
}