当前位置: 首页 > 知识库问答 >
问题:

Java8种不同数据类型的完整期货

盛城
2023-03-14

我有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);
                        }

                     });

    return resultClass;
}

我的问题是:

>

这是处理返回不同结果类型的多个期货的正确方法吗?

在Acceptance Sync中构造ClassD对象是否正确?

共有3个答案

郏稳
2023-03-14

我以前也遇到过类似的情况,并创建了一个简短的演示来展示我是如何解决这个问题的。

类似于@Holger的概念,只是我使用了一个函数来组合每个单独的未来。

https://github.com/te21wals/CompletableFuturesDemo

基本上:

    public class CombindFunctionImpl implement CombindFunction {
    public ABCData combind (ClassA a, ClassB b, ClassC c) {
        return new ABCData(a, b, c);
   }
}

...

    public class FutureProvider {
public CompletableFuture<ClassA> retrieveClassA() {
    return CompletableFuture.supplyAsync(() -> {
        try {
            Thread.sleep(1000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return new ClassA();
    });
}

public CompletableFuture<ClassB> retrieveClassB() {
    return CompletableFuture.supplyAsync(() -> {
        try {
            Thread.sleep(2000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return new ClassB();
    });
}
public CompletableFuture<ClassC> retrieveClassC() {
    return CompletableFuture.supplyAsync(() -> {
        try {
            Thread.sleep(3000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return new ClassC();
    });
}
}

......

public static void main (String[] args){
    CompletableFuture<ClassA> classAfuture = futureProvider.retrieveClassA();
    CompletableFuture<ClassB> classBfuture = futureProvider.retrieveClassB();
    CompletableFuture<ClassC> classCfuture = futureProvider.retrieveClassC();

    System.out.println("starting completable futures ...");
    long startTime = System.nanoTime();

    ABCData ABCData = CompletableFuture.allOf(classAfuture, classBfuture, classCfuture)
            .thenApplyAsync(ignored ->
                    combineFunction.combind(
                            classAfuture.join(),
                            classBfuture.join(),
                            classCfuture.join())
            ).join();

    long endTime = System.nanoTime();
    long duration = (endTime - startTime);
    System.out.println("completable futures are complete...");
    System.out.println("duration:\t" + Duration.ofNanos(duration).toString());
    System.out.println("result:\t" + ABCData);
}
谭学名
2023-03-14

我正沿着与@Holger在他的回答中所做的类似的路线前进,但将服务调用包装在一个可选的中,这导致了在thenApplyAsync阶段更干净的代码

CompletableFuture<Optional<ClassA>> classAFuture
    = CompletableFuture.supplyAsync(() -> Optional.ofNullable(service.getClassA())));

CompletableFuture<Optional<ClassB>> classBFuture
    = CompletableFuture.supplyAsync(() -> Optional.ofNullable(service.getClassB()));

CompletableFuture<Optional<ClassC>> classCFuture
    = CompletableFuture.supplyAsync(() -> Optional.ofNullable(service.getClassC()));

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

        classAFuture.join().ifPresent(resultClass::setClassA)
        classBFuture.join().ifPresent(resultClass::setClassB)
        classCFuture.join().ifPresent(resultClass::setClassC)

        return resultClass;
     });
牛骞仕
2023-03-14

你的尝试正朝着正确的方向发展,但并不正确。您的方法返回一个类型为ClassD的已经实例化的对象,任意线程将在该对象上调用修改方法,而无需调用getResultClassD()的调用方注意。如果修改方法本身不是线程安全的,那么这可能会导致争用情况,此外,调用方永远不会知道实例何时实际可以使用。

正确的解决办法是:

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;
         });
}

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

为了解决其他问题,是的,这个操作是异步的,在lambda表达式中使用join()是合适的<代码>连接正是因为未来而创建的。get(),它被声明为抛出选中的异常,这使得在这些lambda表达式中的使用变得不必要的困难。

请注意,只有当这些测试服务时,空测试才有用。getClassX()实际上可以返回null。如果其中一个服务调用因异常而失败,则整个操作(由CompletableFuture表示)

 类似资料:
  • 我的问题是如何使用Completable Future。 我有一个实现Callable的类。 早点用来做—— 这将返回

  • 我在Java中有两个几乎相同的方法。唯一的区别是它们有不同的参数类型。它们使用泛型并返回输入参数的类型T。我怎样才能摆脱重复的代码?下面是我的两个方法。最后,它们都使用不同的类型调用Spring。否则,方法是相同的。

  • 我正在编写一个实现一些程序分析的Java程序。作为这一点的一部分,我想要一种类型来表示我正在分析的程序中的“值”。在我看来,值只是整数。然而,我宁愿不在代码中使用/类型,因为/不是一个非常描述性的名称。我宁愿写。然后我想写 然后完成。但这不起作用,因为<code>Integer</code>是最终类。因此,我当前的解决方案是给类一个字段,然后手动实现所有各种标准方法: 当我真的只是在寻找行为类似于

  • 我想从数据库中检索不同类型的数据,并从Spring Boot服务的HTTP结果中返回给用户。因为每个数据库检索都需要大量的时间,所以我使用CompletableFuture异步调用这些数据库。与同步进行相比,我所拥有的模式有效且节省了时间,但我觉得它可以也应该以更干净的方式进行布局。 我编辑了代码,将类型更改为“PartA”、“PartB”、“PartC”,但它的外观是这样的。目前,该服务接受不同

  • 我有两个具有FK关系的表。我想要的相当于: 我如何在jOOQ中有效地做到这一点?最后,每个结果行需要一个ARecord实例和一个BRecord实例。

  • 我已经开始了一个使用SpringWebFlux的新项目,我对这种反应式编码范式还相当陌生。所以像新手一样提前道歉。 我的控制器方法将响应返回为