FutureTask
创建线程一般是通过继承Thread或者引入runnable接口,就是不能在执行完成后获取执行的结果,因此Java 1.5之后提供了Callable和Future接口,通过它们就可以在任务执行完毕之后得到任务的执行结果。
Callable接口
对于需要执行的任务需要实现Callable接口,Callable接口定义如下:
publicinterfaceCallable {
/**
* 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() throwsException;
}
可以看到Callable是个泛型接口,泛型V就是要call()方法返回的类型。Callable接口和Runnable接口很像,都可以被另外一个线程执行,但是正如前面所说的,Runnable不会返回数据也不能抛出异常。
Future接口
Future接口代表异步计算的结果,通过Future接口提供的方法可以查看异步计算是否执行完成,或者等待执行结果并获取执行结果,同时还可以取消执行。Future接口的定义如下:
publicinterfaceFuture {
booleancancel(booleanmayInterruptIfRunning);
booleanisCancelled();
booleanisDone();
V get() throwsInterruptedException, ExecutionException;
V get(longtimeout, TimeUnit unit)
throwsInterruptedException, ExecutionException, TimeoutException;
}
cancel():cancel()方法用来取消异步任务的执行。如果异步任务已经完成或者已经被取消,或者由于某些原因不能取消,则会返回false。如果任务还没有被执行,则会返回true并且异步任务不会被执行。如果任务已经开始执行了但是还没有执行完成,若mayInterruptIfRunning为true,则会立即中断执行任务的线程并返回true,若mayInterruptIfRunning为false,则会返回true且不会中断任务执行线程。
isCanceled():判断任务是否被取消,如果任务在结束(正常执行结束或者执行异常结束)前被取消则返回true,否则返回false。
isDone():判断任务是否已经完成,如果完成则返回true,否则返回false。需要注意的是:任务执行过程中发生异常、任务被取消也属于任务已完成,也会返回true。
get():获取任务执行结果,如果任务还没完成则会阻塞等待直到任务执行完成。如果任务被取消则会抛出CancellationException异常,如果任务执行过程发生异常则会抛出ExecutionException异常,如果阻塞等待过程中被中断则会抛出InterruptedException异常。
get(long timeout,Timeunit unit):带超时时间的get()版本,如果阻塞等待过程中超时则会抛出TimeoutException异常。
FutureTask
Future只是一个接口,不能直接用来创建对象,FutureTask是Future的实现类,
FutureTask的继承图如下:
可以看到,FutureTask实现了RunnableFuture接口,则RunnableFuture接口继承了Runnable接口和Future接口,所以FutureTask既能当做一个Runnable直接被Thread执行,也能作为Future用来得到Callable的计算结果。
FutureTask一般配合ExecutorService来使用,也可以直接通过Thread来使用。
第一种
使用例子:
class callable implements Callable{
@Override
public String call()throws Exception {
return "done";
}
}
ExecutorService executorService = Executors.newCachedThreadPool();
Future future = executorService.submit(new callable());
String result = future.get();
第二种
FutureTask futureTask =new FutureTask(new Callable() {
@Override
public String call()throws Exception {
return "done";
}
});
new Thread(futureTask).start();