Guava包中的ListenableFuture详情解析

本文详细解析了Guava中的ListenableFuture接口,它简化了并发编程。ListenableFuture允许添加回调(Callbacks),方便在Future完成后执行操作。推荐使用ListenableFuture代替JDK的Future,因为它提供了更丰富的功能,如Fan-out和Fan-in操作。文章还介绍了如何创建和转换ListenableFuture,并给出了CheckedFuture的概念和用途,以处理可检查异常。示例展示了如何利用ListenableFuture合并多个任务的结果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言:

本章介绍goole Guava 包的 ListenableFuture,也就是开源的Java Library Guaa中的一个并发编程的辅助类,它笨神是继承是java的Future。并发是一个很难的问题,但它是由具有强大和简单的抽象工作显著简化。为了简化事情,Guava扩展了来自JDK的Future从而得到 ListenableFuture。

并发编程是一个难题,但是一个强大而简单的抽象可以显著的简化并发的编写。出于这样的考虑,Guava 定义le ListenableFuture

我们强烈地建议你在代码中多使用ListenableFuture来代替JDK的 Future, 因为:

  • *大多数Futures 方法中需要它。
  • *转到ListenableFuture 编程比较容易。
  • *Guava提供的通用公共类封装了公共的操作方方法,不需要提供Future和ListenableFuture的扩展方法。

接口:

传统JDK中的Future通过异步的方式计算返回结果:在多线程运算中可能或者可能在没有结束返回结果,Future是运行中的
线程的 一个引用 句柄,确保在服务执行返回一个Result。
ListenableFuture可以允许你注册回调方法(callbacks),在运算(多线程执行)完成的时候进行调用,  或者在运算(多线程执行)
完成后 立即执行。这样简单的改进,使得可以明显的支持更多的操作,这样的功能在JDK concurrent包中的Future是不支持的。

  ListenableFuture 中的基础方法是addListener(Runnable, Executor) 该方法会在多线程运算完的时候,指定的Runnable参数传入的对象会被指定的Executor执行。

添加回调(Callbacks):

大多数用户喜欢使用Futures.addCallback(ListenableFuture<V>, FutureCallback<V>, Executor),或默认使用版本MoreExecutors.sameThreadExecutor()以便在回调快速轻便时使用。FutureCallback<V>实现两种方法:

创建:

对应JDK的 ExecutorService.submit(Callable)的方法来启动异步计算,Guava提供的ListeningExecutorService接口,
返回一个ListenableFuture,而ExecutorService将返回普通的Future要转换ExecutorService成一个 ListeningExecutorService
,只需使用 MoreExecutors.listeningDecorator(ExecutorService) 来进行装饰一下即可。

 ListeningExecutorService service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10));
        com.google.common.util.concurrent.ListenableFuture<Object> submit = service.submit(new Callable<Object>() {
            public Object call(){
                return "回调参数success";
            }
        });
        Futures.addCallback(submit, new FutureCallback<Object>() {
            @Override
            public void onSuccess(Object result) {
                System.out.println("result = " + result);
            }

            @Override
            public void onFailure(Throwable t) {
                System.out.println("t = " + t);

            }
        });
另外,如果你是从FutureTask转换而来的,Guava的API提供了   ListenableFutureTask.create(Callable<V>) API转换 ListenableFutureTask.create(Runnable, V) 和 JDK不同的是, ListenableFutureTask 不能随意被继承(译者注:ListenableFutureTask中的done方法实现了调用listener的操作)。

如果你喜欢抽象的方式来设置Future的值,而不是想实现接口中的方法,可以考虑继承抽象类
假如你必须将其它API提供的Future转换成ListenableFuture,没有别的方法你只能采用硬编码的方式,使用JdkFutureAdapters.listenInPoolThread(Future)将其转换FutureListenableFuture尽可能地采用修改原生的代码返回 ListenableFuture会更好一些。

应用(Application):

使用ListenableFuture最重要的理由是它可以进行一系列的复杂链式的异步操作。

ListenableFuture<RowKey> rowKeyFuture = indexService.lookUp(query);
AsyncFunction<RowKey, QueryResult> queryFunction =
  new AsyncFunction<RowKey, QueryResult>() {
    public ListenableFuture<QueryResult> apply(RowKey rowKey) {
      return dataService.read(rowKey);
    }
  };
ListenableFuture<QueryResult> queryFuture =
    Futures.transformAsync(rowKeyFuture, queryFunction, queryExecutor);
许多其他操作可以更有效地支持 ListenableFuture ,而不能单独支持 Future 不同的操作可能由不同的执行者执行,单个操作 ListenableFuture 可以有多个动作等待。

当一个操作开始的时候其他的一些操作也会尽快开始执行–“fan-out”–ListenableFuture 能够满足这样的场景:促发所有的回调(callbacks)。反之更简单的工作是,同样可以满足“fan-in”场景,促发ListenableFuture 获取(get)计算结果,同时其它的Futures也会尽快执行:可以参考Futures.allAsList 

fan-in和fan-out是软件设计的一个术语,可以参考这里:http://baike.baidu.com/view/388892.htm#1或者看这里的解析Design Principles: Fan-In vs Fan-Out,这里fan-out的实现就是封装的ListenableFuture通过回调,调用其它代码片段。fan-in的意义是可以调用其它Future

方法描述参考
transformAsync(ListenableFuture<A>, AsyncFunction<A, B>, Executor)*返回一个新的ListenableFuture ,该ListenableFuture 返回的result是由传入的AsyncFunction 参数指派到传入的 ListenableFuture中.transformAsync(ListenableFuture<A>, AsyncFunction<A, B>)
transform(ListenableFuture<A>, Function<A, B>, Executor)返回一个新的ListenableFuture ,该ListenableFuture 返回的result是由传入的Function 参数指派到传入的 ListenableFuture中.transform(ListenableFuture<A>, Function<A, B>)
allAsList(Iterable<ListenableFuture<V>>)返回一个ListenableFuture ,该ListenableFuture 返回的result是一个List,List中的值是每个ListenableFuture的返回值,假如传入的其中之一fails或者cancel,这个Future fails 或者canceledallAsList(ListenableFuture<V>...)
successfulAsList(Iterable<ListenableFuture<V>>)返回一个ListenableFuture ,该Future的结果包含所有成功的Future,按照原来的顺序,当其中之一Failed或者cancel,则用null替代successfulAsList(ListenableFuture<V>...)
  AsyncFunction<A, B> 提供了一种方法 ListenableFuture<B> apply(A input) 它可以用于异步转换一个值。

List<ListenableFuture<QueryResult>> queries;
// The queries go to all different data centers, but we want to wait until they're all done or failed.

ListenableFuture<List<QueryResult>> successfulQueries = Futures.successfulAsList(queries);

Futures.addCallback(successfulQueries, callbackOnSuccessfulQueries);

CheckedFuture

Guava也提供了一个CheckedFuture<V, X extends Exception>接口 CheckedFutureListenableFuture,包含可以抛出被检查异常的多个get方法的版本。这使得创建一个执行可以更容易地执行可以抛出异常的逻辑。要转换ListenableFuture成a CheckedFuture,使用Futures.makeChecked(ListenableFuture<V>, Function<Exception, X>)。这样使得创建一个在执行逻辑中可以抛出异常的Future更加容易 。将 ListenableFuture 转换成CheckedFuture。使用Futures.makeChecked(ListenableFuture<V>, Function<Exception, X>)

接下来,看一个例子,合并多个人物的结果集

public void test() throws Exception {
        ListeningExecutorService service1 = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(10));
        ListenableFuture<Object> submit1 = service1.submit(new Callable<Object>() {
            @Override
            public Object call() throws Exception {
                Thread.sleep(1000);
                System.out.println("call future1");
                return "1";
            }
        });
        com.google.common.util.concurrent.ListenableFuture<Object> submit2 = service1.submit(new Callable<Object>() {
            @Override
            public Object call() throws Exception {
                Thread.sleep(1000);
                System.out.println("call future2");
                return "2";
            }
        });
        ListenableFuture<List<Object>> listListenableFuture = Futures.allAsList(submit1, submit2);
        ListenableFuture<String> transform = Futures.transform(listListenableFuture, new AsyncFunction<List<Object>, String>() {
            @Override
            public com.google.common.util.concurrent.ListenableFuture<String> apply(List<Object> input) throws Exception {
                return Futures.immediateFuture(String.format("success future %s",input));
            }
        });

        Futures.addCallback(transform, new FutureCallback<String>() {
            @Override
            public void onSuccess(String result) {
                System.out.println(result.getClass());
                System.out.println("success:"+result);
            }

            @Override
            public void onFailure(Throwable t) {
                System.out.println("error:" + t.getMessage());
            }
        });
        //获取值
        System.out.println("transform:"+transform.get(3000, TimeUnit.MINUTES));
    }

下面的例子是单个任务:

 public void test3() throws Exception {
        ListeningExecutorService executorService = MoreExecutors.listeningDecorator(Executors.newCachedThreadPool());
        // 执行任务
        final ListenableFuture<String> listenableFuture =  executorService.submit(new Callable<String>() {
            public String call() throws Exception {
                System.out.println("new task 。。。");
                TimeUnit.SECONDS.sleep(1);
                return "test";
            }

        });
        // 绑定任务以及回调函数
        Futures.addCallback(listenableFuture, new FutureCallback<String>() {
            @Override
            public void onSuccess(String result) {
                String str = "";
                try {
                    str = listenableFuture.get();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }
                System.out.println("integer:" + str);
                System.out.println("result:" + result);
            }

            @Override
            public void onFailure(Throwable t) {
                System.out.println("error" + t.getMessage());
            }}
        );
        System.out.println("listenableFuture:" + listenableFuture.get());
    }
其实除了JDK和Google有Future以外,Spring框架也提供一套Future.下面我们来看一个例子:


ListenableFuture<String> listenableFuture = asyncService.asynGet2();
        SuccessCallback<String> successCallback = new SuccessCallback() {
            @Override
            public void onSuccess(Object result) {
                System.out.println("异步回调success: result :"+result);
            }
        };

        FailureCallback failureCallback = new FailureCallback() {
            @Override
            public void onFailure(Throwable ex) {
                System.out.println("异步回调失败:"+ ex.getMessage());
            }
        };
        listenableFuture.addCallback(successCallback,failureCallback);
        Assert.assertEquals("123",listenableFuture.get());

asyncService 是一个异步Service类,ListenableFuture的返回类型必须通过 new AsyncResult<>()来返回方法的结果集:
new AsyncResult<>()




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值