我有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对象是否正确?
我以前也遇到过类似的情况,并创建了一个简短的演示来展示我是如何解决这个问题的。
类似于@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);
}
我正沿着与@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;
});
你的尝试正朝着正确的方向发展,但并不正确。您的方法返回一个类型为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的新项目,我对这种反应式编码范式还相当陌生。所以像新手一样提前道歉。 我的控制器方法将响应返回为