Java 如何组合3个或更多完成阶段?

Java 如何组合3个或更多完成阶段?,java,concurrency,java-8,Java,Concurrency,Java 8,如果有2个完成阶段,我可以将它们与然后组合方法组合: CompletionStage<A> aCompletionStage = getA(); CompletionStage<B> bCompletionStage = getB(); CompletionStage<Combined> combinedCompletionStage = aCompletionStage.thenCombine(bCompletionStage, (aData, bD

如果有2个完成阶段,我可以将它们与
然后组合
方法组合:

CompletionStage<A> aCompletionStage = getA();
CompletionStage<B> bCompletionStage = getB();
CompletionStage<Combined> combinedCompletionStage =
    aCompletionStage.thenCombine(bCompletionStage, (aData, bData) -> combine(aData, bData));

是否有更好的方法组合多个CompletionStage的结果?

组合多个阶段的唯一方法是使用
CompletableFuture
。如果您的
CompletionStage
s不是
CompletableFuture
s,您仍然可以使用
.toCompletableFuture()
转换它们:

尽管如此,如果你想合并更多的阶段,它的伸缩性并不好


中间解决方案(关于复杂性)可能是:

CompletionStage<Combined> combinedDataCompletionStage = aCompletionStage.thenCompose(
    a -> bCompletionStage.thenCompose(b -> cCompletionStage.thenCompose(
        c -> dCompletionStage.thenApply(d -> combine(a, b, c, d)))));
CompletionStage组合数据CompletionStage=a CompletionStage.then组合(
a->b完成阶段。然后撰写(b->C完成阶段。然后撰写(
c->d完成阶段。然后应用(d->combine(a,b,c,d‘‘‘)’);
它的结构更简单,但仍然不能很好地适应更多的阶段。

可以缩短一点:

CompletionStage<Combined> combinedDataCompletionStage = aCompletionStage.thenCompose(
    a -> bCompletionStage.thenCompose(
        b -> cCompletionStage.thenCombine(dCompletionStage,
            (c, d) -> combine(a, b, c, d))));
CompletionStage组合数据CompletionStage=a CompletionStage.then组合(
a->B完成阶段。然后撰写(
b->cCompletionStage。然后合并(dCompletionStage,
(c,d)->组合(a,b,c,d));

我认为您应该使用一个中间对象,而不是使用
Pair
Tuple

public R method() {
    CompletableFuture<A> aFuture = getAFuture();
    CompletableFuture<B> bFuture = getBFuture();
    CompletableFuture<C> cFuture = getCFuture();
    CompletableFuture<D> dFuture = getDFuture();

    return CompletableFuture.completedFuture(new WellNamedResultHolder())
            .thenCombineAsync(aFuture, WellNamedResultHolder::withAResult)
            .thenCombineAsync(bFuture, WellNamedResultHolder::withBResult)
            .thenCombineAsync(cFuture, WellNamedResultHolder::withCResult)
            .thenCombineAsync(dFuture, WellNamedResultHolder::withDResult)
            .thenApplyAsync(this::combineAllTheResults);
}

private static class WellNamedResultHolder {
    private A aResult;
    private B bResult;
    private C cResult;
    private D dResult;

    // Getters

    public WellNamedResultHolder withAResult(final A aResult) {
        this.aResult = aResult;
        return this;
    }

    public WellNamedResultHolder withBResult(final B bResult) {
        this.bResult = bResult;
        return this;
    }

    public WellNamedResultHolder withCResult(final C cResult) {
        this.cResult = cResult;
        return this;
    }

    public WellNamedResultHolder withDResult(final D dResult) {
        this.dResult = dResult;
        return this;
    }
}
public R方法(){
CompletableFuture-aFuture=getAFuture();
CompletableFuture bFuture=getBFuture();
CompletableFuture cFuture=getCFuture();
CompletableFuture-dFuture=getDFuture();
返回CompletableFuture.completedFuture(新的WellNamedResultHolder())
.然后组合同步(未来,井名结果持有人::WitherResult)
.thenCombineAsync(b未来,井名结果持有者::withBResult)
.然后组合同步(C未来,井名结果持有人::withCResult)
.thenCombineAsync(数据未来,井名结果持有者::withDResult)
.然后应用同步(此::组合所有结果);
}
私有静态类WellNamedResultHolder{
私人结果;
私人B-bResult;
私人C cResult;
私人D dResult;
//吸气剂
具有最终结果的公共油井名称结果持有人(最终结果){
this.aResult=aResult;
归还这个;
}
具有bResult(最终B bResult)的公共油井名称结果持有人{
this.bResult=bResult;
归还这个;
}
公共油井名称结果持有人(最终C结果){
this.cResult=cResult;
归还这个;
}
具有dResult的公共井名dResult持有人(最终D dResult){
this.dResult=dResult;
归还这个;
}
}
结果持有者的实际形式可以明显地改变,以满足您自己的需要,给您更大的灵活性。当这些期货交易完成时,你也要对所发生的事情负责。尽管有更多的样板文件,但您得到的代码更能描述正在发生的事情(lombok可以整理)。

您询问了“3个或更多”,如果您将它们作为CompletableFutures(参见其他答案)列在列表中,您可以使用以下简便方法:

private static <T> CompletableFuture<List<T>> join(List<CompletableFuture<T>> executionPromises) {
    CompletableFuture<Void> joinedPromise = CompletableFuture.allOf(executionPromises.toArray(CompletableFuture[]::new));
    return joinedPromise.thenApply(voit -> executionPromises.stream().map(CompletableFuture::join).collect(Collectors.toList()));
}
私有静态CompletableFuture连接(列表执行承诺){
CompletableFuture joinedPromise=CompletableFuture.allOf(executionPromises.toArray(CompletableFuture[]::new));
返回joinedPromise.thenApply(voit->executionPromises.stream().map(CompletableFuture::join).collect(Collectors.toList());
}

它将您的“未来列表”转换为“结果列表的未来”。

我有一个类似的问题,但有3个以上可完成的未来,所以在回答的基础上,我制作了一个小型通用工具

public static <T, R> CompletableFuture<R> allOf(List<CompletableFuture<T>> args, Function<List<T>, R> combiner) {
    final Queue<CompletableFuture<T>> queue = new LinkedList<>();
    for (CompletableFuture<T> arg : args) {
        queue.add(arg);
    }
    return aggregator(queue, new ArrayList<>(), combiner);
}

private static <T, R> CompletableFuture<R> aggregator(Queue<CompletableFuture<T>> queue, List<T> arg,
        Function<List<T>, R> combiner) {
    if (queue.size() == 2)
        return queue.poll().thenCombine(queue.poll(), (c, d) -> {
            arg.add(c);
            arg.add(d);
            return combiner.apply(arg);
        });
    return queue.poll().thenCompose(data -> {
        arg.add(data);
        return aggregator(queue, arg, combiner);
    });
}
公共静态CompletableFuture allOf(列表参数、函数组合器){
最终队列=新建LinkedList();
用于(可完成的未来参数:参数){
queue.add(arg);
}
返回聚合器(队列、新ArrayList()、合并器);
}
专用静态CompletableFuture聚合器(队列、列表参数、,
函数组合器){
if(queue.size()==2)
返回queue.poll().thenCombine(queue.poll(),(c,d)->{
arg.添加(c);
参数添加(d);
返回合并器。应用(arg);
});
返回queue.poll().thenCompose(数据->{
参数添加(数据);
返回聚合器(队列、参数、组合器);
});
}

我认为completablefuture.allOf()函数可以帮助您

例如:(查看完整类)

列出URL=[
"https://webhook.site/1647465b-c28f-4ffe-bbfe-5d3ad95ef994",
"https://webhook.site/1647465b-c28f-4ffe-bbfe-5d3ad95ef994?a=1"
]
CompletableFuture[]期货=新的CompletableFuture[2]
对于(int i=0;i
return futures.collect{it.join()}
}.thenApply({响应->
//对结果做点什么
responses.each{println(“状态代码:+it.statusCode)}
})

可以组合(减少)任意数量的CompletableFuture

CompletionStage futA=getA();
CompletionStage futB=getB();
CompletionStage futC=getC();
流量(futA、futB、futC)
.减少((f1,f2)->f1.然后合并(f2,(d1,d2)->合并(d1,d2));

combine方法的实现将负责合并数据值(A、B和C),如果A、B和C是不同的,这可能会很棘手。

您可以创建一个助手函数

combine3(
未来,未来B,未来C,
(a、b、c)->{
//我们走吧!
}).toCompletableFuture();
定义:

专用静态完成阶段组合3(
完成阶段A阶段,
完成阶段b阶段,
完成阶段cStage,
三函数f
) {
返回aStage.thenCompose(
a->b阶段。然后组合(c阶段,
(b,c)->f.应用(a,b,c));
}
接口TriF
public R method() {
    CompletableFuture<A> aFuture = getAFuture();
    CompletableFuture<B> bFuture = getBFuture();
    CompletableFuture<C> cFuture = getCFuture();
    CompletableFuture<D> dFuture = getDFuture();

    return CompletableFuture.completedFuture(new WellNamedResultHolder())
            .thenCombineAsync(aFuture, WellNamedResultHolder::withAResult)
            .thenCombineAsync(bFuture, WellNamedResultHolder::withBResult)
            .thenCombineAsync(cFuture, WellNamedResultHolder::withCResult)
            .thenCombineAsync(dFuture, WellNamedResultHolder::withDResult)
            .thenApplyAsync(this::combineAllTheResults);
}

private static class WellNamedResultHolder {
    private A aResult;
    private B bResult;
    private C cResult;
    private D dResult;

    // Getters

    public WellNamedResultHolder withAResult(final A aResult) {
        this.aResult = aResult;
        return this;
    }

    public WellNamedResultHolder withBResult(final B bResult) {
        this.bResult = bResult;
        return this;
    }

    public WellNamedResultHolder withCResult(final C cResult) {
        this.cResult = cResult;
        return this;
    }

    public WellNamedResultHolder withDResult(final D dResult) {
        this.dResult = dResult;
        return this;
    }
}
private static <T> CompletableFuture<List<T>> join(List<CompletableFuture<T>> executionPromises) {
    CompletableFuture<Void> joinedPromise = CompletableFuture.allOf(executionPromises.toArray(CompletableFuture[]::new));
    return joinedPromise.thenApply(voit -> executionPromises.stream().map(CompletableFuture::join).collect(Collectors.toList()));
}
public static <T, R> CompletableFuture<R> allOf(List<CompletableFuture<T>> args, Function<List<T>, R> combiner) {
    final Queue<CompletableFuture<T>> queue = new LinkedList<>();
    for (CompletableFuture<T> arg : args) {
        queue.add(arg);
    }
    return aggregator(queue, new ArrayList<>(), combiner);
}

private static <T, R> CompletableFuture<R> aggregator(Queue<CompletableFuture<T>> queue, List<T> arg,
        Function<List<T>, R> combiner) {
    if (queue.size() == 2)
        return queue.poll().thenCombine(queue.poll(), (c, d) -> {
            arg.add(c);
            arg.add(d);
            return combiner.apply(arg);
        });
    return queue.poll().thenCompose(data -> {
        arg.add(data);
        return aggregator(queue, arg, combiner);
    });
}
    List<String> urls = [
            "https://webhook.site/1647465b-c28f-4ffe-bbfe-5d3ad95ef994",
            "https://webhook.site/1647465b-c28f-4ffe-bbfe-5d3ad95ef994?a=1"
    ]
    CompletableFuture<Response>[] futures = new Completablefuture[2]
    for (int i = 0; i < urls.size(); i++) {
        futures[i] = asyncHttpClient.prepareGet(urls[i]).execute().toCompletableFuture()

    }

    CompletableFuture.allOf(futures).thenApply { future ->
        return futures.collect { it.join() }
    }.thenApply({ responses ->
        //Do something with results
        responses.each { println("Status code: " + it.statusCode) }
    })
CompletionStage<A> futA = getA();
CompletionStage<B> futB = getB(); 
CompletionStage<C> futC = getC(); 

Stream.of(futA, futB, futC) 
    .reduce((f1, f2) -> f1.thenCombine(f2, (d1, d2) -> combine(d1, d2));