Runnable 接口,由于是 void 方法,是没有返回结果的,在并发包中,有 Callable 类,能够得到执行的结果。
Callable
返回结果并且可能抛出异常的任务。实现者定义了一个不带任何参数的叫做 call 的方法。
Callable 接口类似于 Runnable,两者都是为那些其实例可能被另一个线程执行的类设计的。但是 Runnable 不会返回结果,并且无法抛出经过检查的异常。
public interface Callable<V> {
// 计算结果,如果无法计算结果,则抛出一个异常
V call() throws Exception;
}
Callable一般是和ExecutorService配合来使用的。
Future
Future 表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并获取计算的结果。
public interface Future<V> {
// 试图取消对此任务的执行
boolean cancel(boolean mayInterruptIfRunning);
// 如果在任务正常完成前将其取消,则返回true
boolean isCancelled();
// 如果任务已完成,则返回true
boolean isDone();
// 如有必要,等待计算完成,然后获取其结果
V get() throws InterruptedException, ExecutionException;
// 如有必要,最多等待为使计算完成所给定的时间之后,获取其结果(如果结果可用)
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
RunnableFuture
作为 Runnable 的 Future。成功执行 run 方法可以完成 Future 并允许访问其结果。
public interface RunnableFuture<V> extends Runnable, Future<V> {
// 在未被取消的情况下,将此Future设置为计算的结果
void run();
}
FutureTask
实现 RunnableFuture 接口,既可以作为 Runnable 被执行,也可以作为 Future 得到 Callable 的返回值。
从下边构造函数可以看出,可以接受 Callable 或 Runnable 来创建 FutrueTask 。
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW; // ensure visibility of callable
}
public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
this.state = NEW; // ensure visibility of callable
}
使用方法
public class TestExecutor {
public static void main(String[] args) throws InterruptedException, ExecutionException {
System.out.println("主线程执行");
ExecutorService executor = Executors.newCachedThreadPool();
Future<Integer> result = executor.submit(new CountTask());
executor.shutdown();
Integer i = result.get();
System.out.println("主线程结束");
System.out.println("主线程获取子线程结果为:" + i);
}
public static class CountTask implements Callable<Integer>{
@Override
public Integer call() throws Exception {
System.out.println("子线程开始计算");
Thread.sleep(5000);
System.out.println("子线程结束计算,共用时5秒");
return 100;
}
}
}
运行结果为:
主线程执行
子线程开始计算
子线程结束计算,共用时5秒
主线程结束
结果为:100
在例子中,如果要使用 FutureTask ,应这样:
ExecutorService executor = Executors.newCachedThreadPool();
// Future的使用
//Future<Integer> result = executor.submit(new CountTask());
// FutureTask的使用
FutureTask<Integer> futureTask = new FutureTask<>(new CountTask());
executor.submit(futureTask);
executor.shutdown();
// Future获取结果
//Integer i = result.get();
// futureTask获取结果
Integer i = futureTask.get();