上一篇,Guava库学习:学习Concurrency(三)ListenableFuture中, 我们最后说到,ListenableFuture.addListener方法并没有返回值,我们不能区别的处理任务成功后失败的情况,Guava提供了 FutureCallback接口,FutureCallback接口提供了onSuccess 和onFailure 方法,onSuccess 方法以Future任务的执行结果作为参数,因此我们就可以在成功时候获取任务执行的结果,做进一步的处理了,本篇,我们就来进行 Concurrency(四)FutureCallback接口的学习。
使用FutureCallback
使用 FutureCallback非常简单,我们以类似的方式向ListenableFuture注册一个回调接口,我们不需要直接向 ListenableFuture添加FutureCallback回调函数,而是直接使用Futures.addCallback方法。Futures 类提供了一些有用的、用于处理Future实例的静态方法集合,接下来我们来看一个例子,首先来看一个简单的FutureCallback接口的实现:
class FutureCallbackImpl implements FutureCallback<String> { private StringBuilder builder = new StringBuilder(); @Override public void onSuccess(String result) { builder.append(result).append(" successfully"); } @Override public void onFailure(Throwable t) { builder.append(t.toString()); } public String getCallbackResult() { return builder.toString(); } }
在上面的例子中,我们在onSuccess方法中捕获到了任务执行的结果,并将结果追加字符" successfully",在异常的情况下,我们通过Throwable对象获取到了异常信息,来看下面的一个完整的应用例子,如下:
@Test public void testFutureCallback() { // 创建一个线程缓冲池Service ExecutorService executor = Executors.newCachedThreadPool(); //创建一个ListeningExecutorService实例 ListeningExecutorService executorService = MoreExecutors.listeningDecorator(executor); //提交一个可监听的线程 ListenableFuture<String> futureTask = executorService.submit (new Callable<String>() { @Override public String call() throws Exception { return "Task completed"; } }); FutureCallbackImpl callback = new FutureCallbackImpl(); //线程结果处理回调函数 Futures.addCallback(futureTask, callback); //如果callback中执行的是比较费时的操作,Guava建议使用以下方法。 // Futures.addCallback(futureTask,callback,executorService); //处理后的线程执行结果:"Task completed successfully" assertThat(callback.getCallbackResult(), is("Task completed successfully")); }
在上面的例子中,我们创建了一个ListenableFuture接口和一个FutureCallback接口的实现,并且注册,在 ListenableFuture实例完成后会立即执行回调函数,并且能够准确的捕获到执行结果进行处理。通常情况下,我们不想从 FutureCallback实例访问结果,而是让FutureCallback异步处理结果。如果提供的FutureCallback实例 执行的是比较费时的操作,使用如下的Futures.addCallback方法可能比较好:
Futures.addCallback(futureTask,callback,executorService);
注:关于Futures,请参阅:Guava库学习:学习Concurrency(八)Futures
通过这个方法,FutureCallback操作将会执行在单独的线程,这个线程由传入的ExecutorService参数提供。否则的话,初始 ListenableFuture实例执行的线程将会执行FutureCallback操作,就像ThreadPoolExecutor、 CallerRunsPolicy执行者服务,即任务将在调用者的线程上运行。
总结:FutureCallback接口用于处理任务完成或失败后的结果,适用于在多线程并发编程中对Future结果的获取和处理,是对ListenableFuture接口很好的补充,弥补了ListenableFuture接口无法处理任务返回值的缺陷。