Java 8 Completable Futures allOf不同的数据类型 [英] Java 8 Completable Futures allOf different data types

查看:351
本文介绍了Java 8 Completable Futures allOf不同的数据类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有3个CompletableFutures,所有3个返回不同的数据类型。



我希望创建一个结果对象,它是所有3个期货返回的结果的组合。



所以我目前的工作代码如下所示:

  public ClassD getResultClassD(){

ClassD resultClass = new ClassD();
CompletableFuture< ClassA> classAFuture = CompletableFuture.supplyAsync(() - > service.getClassA());
CompletableFuture< ClassB> classBFuture = CompletableFuture.supplyAsync(() - > service.getClassB());
CompletableFuture< ClassC> classCFuture = CompletableFuture.supplyAsync(() - > service.getClassC());

CompletableFuture.allOf(classAFuture,classBFuture,classCFuture)
.thenAcceptAsync(it - > {
ClassA classA = classAFuture.join();
if(classA) != null){
resultClass.setClassA(classA);
}

ClassB classB = classBFuture.join();
if(classB!= null){
resultClass.setClassB(classB);
}

ClassC classC = classCFuture.join();
if(classC!= null){
resultClass .setClassC(classC);
}

});

返回resultClass;
}

我的问题是:


  1. 我的假设是因为我使用 allOf 然后接受Async 此通话将无阻塞。我的理解是对的吗?


  2. 这是处理多种期货的正确方法吗?


  3. thenAcceptAsync 中构建 ClassD 对象是对的吗?


  4. 在thenAcceptAsync lambda中使用 join getNow 方法是否合适?


解决方案

您的尝试正朝着正确的方向发展,但不正确。你的方法 getResultClassD()返回一个已经实例化的类型为 ClassD 的对象,任意线程将在其上调用修改方法, 的调用者getResultClassD()注意到。这可能会导致竞争条件,如果修改方法本身不是线程安全的,那么当 ClassD 实例实际可以使用时,调用者永远不会知道。 / p>

正确的解决方案是:

  public CompletableFuture< ClassD> getResultClassD(){

CompletableFuture< ClassA> classAFuture
= CompletableFuture.supplyAsync(() - > service.getClassA());
CompletableFuture< ClassB> classBFuture
= CompletableFuture.supplyAsync(() - > service.getClassB());
CompletableFuture< ClassC> classCFuture
= CompletableFuture.supplyAsync(() - > service.getClassC());

返回CompletableFuture.allOf(classAFuture,classBFuture,classCFuture)
.thenApplyAsync(dummy - > {
ClassD resultClass = new ClassD();

ClassA classA = classAFuture.join();
if(classA!= null){
resultClass.setClassA(classA);
}

ClassB classB = classBFuture .join();
if(classB!= null){
resultClass.setClassB(classB);
}

ClassC classC = classCFuture.join();
if(classC!= null){
resultClass.setClassC(classC);
}

return resultClass;
});
}

现在,的调用者getResultClassD()可以使用返回的 CompletableFuture 来查询进度状态或链依赖操作或使用 join()操作完成后检索结果。



要解决其他问题,是的,此操作是异步的并且使用 join( lambda表达式中的是合适的。 join 是完全创建的,因为 Future.get(),它被声明为抛出已检查的异常,在这些内部使用lambda表达式不必要地很难。



注意 null 测试只有在这些时才有用service.getClassX()实际上可以返回 null 。如果其中一个服务调用因异常而失败,则整个操作(由 CompletableFuture< ClassD> 表示)将异常完成。


I have 3 CompletableFutures all 3 returning different data types.

I am looking to create a result object that is a composition of the result returned by all the 3 futures.

So my current working code looks like this:

public ClassD getResultClassD() {

    ClassD resultClass = new ClassD();
    CompletableFuture<ClassA> classAFuture = CompletableFuture.supplyAsync(() -> service.getClassA() );
    CompletableFuture<ClassB> classBFuture = CompletableFuture.supplyAsync(() -> service.getClassB() );
    CompletableFuture<ClassC> classCFuture = CompletableFuture.supplyAsync(() -> service.getClassC() );

    CompletableFuture.allOf(classAFuture, classBFuture, classCFuture)
                     .thenAcceptAsync(it -> {
                        ClassA classA = classAFuture.join();
                        if (classA != null) {
                            resultClass.setClassA(classA);
                        }

                        ClassB classB = classBFuture.join();
                        if (classB != null) {
                            resultClass.setClassB(classB);
                        }

                        ClassC classC = classCFuture.join();
                        if (classC != null) {
                            resultClass.setClassC(classC);
                        }

                     });

    return resultClass;
}

My questions are:

  1. My assumption here is that since I am using allOf and thenAcceptAsync this call will be non blocking. Is my understanding right ?

  2. Is this the right way to deal with multiple futures returning different result types ?

  3. Is it right to construct ClassD object within thenAcceptAsync ?

  4. Is it appropriate to use the join or getNow method in the thenAcceptAsync lambda ?

解决方案

Your attempt is going into the right direction, but not correct. Your method getResultClassD() returns an already instantiated object of type ClassD on which an arbitrary thread will call modifying methods, without the caller of getResultClassD() noticing. This can cause race conditions, if the modifying methods are not thread safe on their own, further, the caller will never know, when the ClassD instance is actually ready for use.

A correct solution would be:

public CompletableFuture<ClassD> getResultClassD() {

    CompletableFuture<ClassA> classAFuture
        = CompletableFuture.supplyAsync(() -> service.getClassA() );
    CompletableFuture<ClassB> classBFuture
        = CompletableFuture.supplyAsync(() -> service.getClassB() );
    CompletableFuture<ClassC> classCFuture
        = CompletableFuture.supplyAsync(() -> service.getClassC() );

    return CompletableFuture.allOf(classAFuture, classBFuture, classCFuture)
         .thenApplyAsync(dummy -> {
            ClassD resultClass = new ClassD();

            ClassA classA = classAFuture.join();
            if (classA != null) {
                resultClass.setClassA(classA);
            }

            ClassB classB = classBFuture.join();
            if (classB != null) {
                resultClass.setClassB(classB);
            }

            ClassC classC = classCFuture.join();
            if (classC != null) {
                resultClass.setClassC(classC);
            }

            return resultClass;
         });
}

Now, the caller of getResultClassD() can use the returned CompletableFuture to query the progress state or chain dependent actions or use join() to retrieve the result, once the operation is completed.

To address the other questions, yes, this operation is asynchronous and the use of join() within the lambda expressions is appropriate. join was exactly created because Future.get(), which is declared to throw checked exceptions, makes the use within these lambda expressions unnecessarily hard.

Note that the null tests are only useful, if these service.getClassX() can actually return null. If one of the service calls fails with an exception, the entire operation (represented by CompletableFuture<ClassD>) will complete exceptionally.

这篇关于Java 8 Completable Futures allOf不同的数据类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆