在Java中,我们知道创建线程有两种方式,继承Thread类或者实现Runnable 接口,但是这两种方式都是不能获取方法返回结果的。如果想获取结果,就需要做一些额外的处理,利用共享变量,线程间通信等方式,使用起来就不是很方便,对于不熟悉的人还可能出现线程安全问题。jdk1.5之后,提供了FutureTask类,以及Callable、Future接口,实现了对异步获取返回结果的支持。
public interface Callable {
V call() throws Exception;
}
Callable接口是一个泛型接口,只有一个方法,并且有一个返回值,就是泛型V。call方法就是线程实际执行的方法。
Future接口描述了获取返回结果的方法。
public interface Future {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
public class FutureTask implements RunnableFuture
public interface RunnableFuture extends Runnable, Future
FutureTask实现了RunnableFuture接口,而RunnableFuture接口继承Runnable与Future接口。
从Thread的构造函数中,可以看出FutureTask还是以Runnable作为参数传入,因此线程中调用的还是FutureTask的run方法,既然run方法没有返回值,FutureTask应该是使用的某种机制调用了有返回值的call方法。
public FutureTask(Callable callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
FutureTask构造函数需要提供一个Callable实现类作为参数,构造函数中又一个state变量被赋值为NEW,用于标记线程状态。
public void run() {
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable 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 must be non-null until state is settled to
// prevent concurrent calls to run()
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
在FutureTask的run方法中,显式调用了Callable的call方法,并将返回值赋值给result,然后在set(result)中,存入outcome并更新state状态,唤醒等待结果的线程,outcome就是所需要的结果。f
protected void set(V v) {
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
outcome = v; //赋值给outcome
UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
finishCompletion(); //唤醒等待线程等
}
}
get方法用于获取异步执行返回值,如果执行完成,则返回结果,如果未完成,就进入等待。
public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)
s = awaitDone(false, 0L);
return report(s);
}