Future要获取异步任务执行的结果,需要通过轮询或者阻塞等待的方式,这样的方式,总显得不太“完美”,比较好的做法,应该是异步执行结束后,去通知用户异步任务结束了,你可以通过Future来获取执行结果了。
ListenableFuture 顾名思义可以监听Future,它是对java原生Future的扩展增强。我们知道Future表示一个异步计算任务,当任务完成时可以得到计算结果。如果我们希望一旦计算完就拿到结果展示给用户或者做另外的计算,就必须使用另一个线程不断的查询计算状态。这样做,代码复杂,而且效率底下。使用ListenableFuture guava帮我们检测Future是否完成了,如果完成了就自动调用回调函数,这样可以减少并发程序的复杂度。
public class AddTask implements Callable<Integer> {
private int a,b;
public AddTask(int a, int b) {
this.a = a;
this.b = b;
}
public Integer call() throws Exception {
return a+b;
}
public static void main(String[] args) throws InterruptedException, ExecutionException {
ExecutorService executorService = Executors.newSingleThreadExecutor();
Future<Integer> future = executorService.submit(new AddTask(1,2));
Thread.sleep(5000);
//只有当future的状态是已完成时(future.isDone = true),get方法才会返回
if(future.isDone()){
System.out.println(future.get());
}
}
}
对应JDK中的ExecutorService.submit(Callable)提交多线程异步运算的方式,guava提供了ListeningExecutorService接口,该接口返回ListenableFuture,而相应的Executor返回普通的Future。将ExecutorService转为ListeningExecutorService,可以使用MoreExecutors.listenintDecorator(ExecutorService)进行装饰。
ListeningExecutorService guavaExecutor = MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor());
提交Callable任务
final ListenableFuture<String> future = pool.submit(new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(1000*3);
return "Task done !";
}
});
添加Listener
future.addListener(new Runnable() {
@Override
public void run() {
try {
final String contents = future.get();
System.out.println(contents);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}, MoreExecutors.sameThreadExecutor());
上面的代码,确实不怎么优雅,我们需要处理抛出的异常,需要自己通过future.get()获得前面计算的值。guava提供的一个简单方法如下:
Futures.addCallback(future, new FutureCallback<String>() {
@Override
public void onSuccess(String result) {
System.out.println(result);
}
@Override
public void onFailure(Throwable t) {
t.printStackTrace();
}
});
可以在成功和失败写相应的逻辑代码