无论是从类Thread继承还是实现Runnable接口来创建线程,方法run是没有返回值的 。线程可不可以有一个返回值?答案是肯定的。带返回值的线程可以通过接口Callable来定义,并通过接口Future来获得线程的返回值。
接口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中有一个call()函数,call()函数有返回值。可以看到,这是一个泛型接口,call()函数返回的类型就是客户程序传递进来的V类型。这里只定义了线程会有返回值,其返回值是通过Future来获得的。
接口Future
接口Future允许在未来某个时间获得线程运行的结果,它保存了使用Callable接口定义的线程异步运行结果。当启动一个Future对象后,相当于启动了一个计算,然后可以去做别的事,Future对象的计算结果将在计算好后得到。
在Future接口中声明了如下5个方法:
public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
cancel方法:用来取消任务,如果取消任务成功则返回true,如果取消任务失败则返回false。参数mayInterruptIfRunning表示是否允许取消正在执行却没有执行完毕的任务,如果设置true,则表示可以取消正在执行过程中的任务。如果任务已经完成,则无论mayInterruptIfRunning为true还是false,此方法肯定返回false,即如果取消已经完成的任务会返回false;如果任务正在执行,若mayInterruptIfRunning设置为true,则返回true,若mayInterruptIfRunning设置为false,则返回false;如果任务还没有执行,则无论mayInterruptIfRunning为true还是false,肯定返回true。
isCancelled方法:表示任务是否被取消成功,如果在任务正常完成前被取消成功,则返回 true。
isDone方法:表示任务是否已经完成,若任务完成,则返回true;
get()方法:用来获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回;
get(long timeout, TimeUnit unit)方法:用来获取执行结果,如果在指定时间内,还没获取到结果,就直接返回null。
也就是说Future提供了三种功能:
1)判断任务是否完成;
2)能够中断任务;
3)能够获取任务执行结果。
因为Future只是一个接口,所以是无法直接用来创建对象使用的,因此就有了下面的FutureTask。
FutureTask
public class FutureTask<V> implements RunnableFuture<V> {}
public interface RunnableFuture<V> extends Runnable, Future<V> {}
FutureTask包装器同时实现了接口Runnable和接口Future,他可以很方便地对Callable对象进行封装并转换成Future对象,FutureTask的构造方法定义如下:
public FutureTask(Callable<V> callable) {
}
public FutureTask(Runnable runnable, V result) {
}
实例演示
public class UseFuture {
/*实现Callable接口,允许有返回值*/
private static class UseCallable implements Callable<Integer>{
private int sum;
@Override
public Integer call() throws Exception {
System.out.println("Callable子线程开始计算!");
Thread.sleep(2000);
for(int i=0 ;i<5000;i++){
sum=sum+i;
}
System.out.println("Callable子线程计算结束!结果为: "+sum);
return sum;
}
}
public static void main(String[] args)
throws InterruptedException, ExecutionException {
UseCallable useCallable = new UseCallable();
FutureTask<Integer> futureTask //用FutureTask包装Callable
= new FutureTask<>(useCallable);
new Thread(futureTask).start();//交给Thread去运行
Random r = new Random();
Thread.sleep(1000);
if(r.nextBoolean()) {//用随机的方式决定是获得结果还是终止任务
System.out.println("Get UseCallable result = "+futureTask.get());
}else {
System.out.println("中断计算。 ");
futureTask.cancel(true);
}
}
}