Thread类的run方法返回值类型是void,因此我们无法直接通过Thread类获取线程执行结果。如果要获取线程执行结果就需要使用FutureTask。用法如下:
class CallableImpl implements Callable{
@Override
public Object call() throws Exception {
//do somethings
//return result;
}
}
FutureTask futureTask = new FutureTask(new CallableImpl());
new Thread(futureTask).start();
try {
//获取线程执行结果
Object result = futureTask.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
在实例化FutureTask时构造函数传入了实现Callable接口的实例。而在实例化Thread类时,构造函数传入FutureTask实例。因此,我们可以猜测线程在执行run方法时必定会调用call方法,并且保存call方法返回的结果。
总览
通过类图,可以看到FutureTask主要实现了Runnable和Future。实现Runnable的run方法作为线程的执行体。正因为实现了Runnable,我们才可以使用FutureTask来创建线程。Future接口定义了如下几个方法
public interface Future<V> {
/**
*取消线程执行的任务
*/
boolean cancel(boolean mayInterruptIfRunning);
/**
*判断任务是否被取消
*如果任务在正常完成前因调用cancel方法而被取消,返回true
*/
boolean isCancelled();
/**
* 判断任务是否完成,如果任务已经完成,返回true
* 完成可能是由于正常终止、异常或取消——在这些情况下,此方法都将返回true。
*/
boolean isDone();
/**
* 获取任务执行的结果,调用该方法时,如果任务还没有执行完成,将会阻塞当前线程
* 直到任务完成或者被中断
*/
V get() throws InterruptedException, ExecutionException;
/**
* 获取任务执行的结果,调用该方法时,如果任务还没有执行完成,将会阻塞当前线程
* 直到任务完成或者被中断或者超时
*/
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
可以看出FutureTask具备获取线程任务执行结果、取消线程任务的能力。
成员变量
public class FutureTask<V> implements RunnableFuture<V> {
//state标识任务的运行状态
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;
//任务的执行体,任务完成后,将会设置成null
private Callable<V> callable;
//任务执行体的返回结果
private Object outcome;
//运行callable的线程
private volatile Thread runner;
//等待任务执行结果的线程队列
private volatile WaitNode waiters;
static final class WaitNode {
//当前节点代表的线程
volatile Thread thread;
//下一个节点
volatile WaitNode next;
WaitNode() { thread = Thread.currentThread(); }
}
}