java—当一个结果依赖于另一个结果时,如何组合completablefuture的两个结果?

rjzwgtxy  于 2021-07-06  发布在  Java
关注(0)|答案(2)|浏览(502)

有两种服务:
service1返回ids1的列表;
service2按id1返回ids2的列表:
如何使用completablefuture按id1->[id2,id2,id2,…]对结果进行分组?我想把它全部放到hashmap中,但我不知道如何将ids1传递到第二个未来。我在考虑使用thencombine(ids1future,(v1,v2)->{…}),但在我看来它相当难看。有什么“最佳实践”可以做到这一点吗?
这里不是异步方式:

Map<ID1, List<ID2>> idsMap = new HashMap();

  List<IDS1> ids1List = service1.service.find();

  for(ID1 id1: IDS1) {
    List<IDS2> ids2List = service2.findById(id1);
    idsMap.put(id1, ids2List);
  }
  service2.process(idsMap);

绑定异步执行:

CompletableFuture<List<IDS1>> ids1Future
            = CompletableFuture.supplyAsync(() -> service.find());

    ids1Future.thenApply((ids1) -> {
        CompletableFuture<List<IDS2>> listFutureIds2 = 
  ids1.stream().map(id1 ->
                CompletableFuture.supplyAsync(() -> 
   service2.getById(id1)))
                .collect(Collectors.toList());

        CompletableFuture<Void> allFuturesDone =
                CompletableFuture.allOf(
                        listFutureIds2.toArray(
                            new 
  CompletableFuture[listFutureIds2.size()]));
        allFuturesDone.thenApply(v ->
                list.stream()
                        .map(CompletableFuture::join)
                        .collect(toList()));

    });
bz4sfanl

bz4sfanl1#

我希望我正确地理解了你的意思,所以这里是:

CompletableFuture<List<IDS1>> ids1Future = CompletableFuture.supplyAsync(service::find);

   CompletableFuture<Map<IDS1, List<IDS2>>> map = ids1Future.thenApply(listIDS1 -> {
        List<Entry<IDS1, CompletableFuture<List<IDS2>>>> list =
            listIDS1
                .stream()
                .map(ids1 -> new SimpleEntry<>(ids1, CompletableFuture.supplyAsync(() -> service2.getById(ids1))))
                .collect(Collectors.toList());

        return list.stream()
                   .map(entry -> new SimpleEntry<>(entry.getKey(), entry.getValue().join()))
                   .collect(Collectors.toMap(Entry::getKey, Entry::getValue));

    });

    Map<IDS1, List<IDS2>> result = map.join();
rkttyhzu

rkttyhzu2#

这是一个如何使用fork/join将字符列表转换为字符串列表的示例,其中每个字符串是字符的n倍的复制。你可以根据自己的情况调整这个例子。
我希望这就是你要找的。

import java.util.Collection;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;
import java.util.stream.Collectors;

public class ForkJoinExample {

    public static class RepeatTask extends RecursiveTask<List<String>> {

        private final List<Character> chars;
        private final int repeatCount;

        public RepeatTask(List<Character> chars, int repeatCount) {
            this.chars = chars;
            this.repeatCount = repeatCount;
        }

        public RepeatTask(Character c, int repeatCount) {
            this.chars = List.of(c);
            this.repeatCount = repeatCount;
        }

        @Override
        protected List<String> compute() {
            if (chars.size() > 1) {
                ForkJoinTask.invokeAll(chars.stream().map(c -> new RepeatTask(c, repeatCount)).collect(Collectors.toList()));
                return ForkJoinTask.invokeAll(chars.stream().map(c -> new RepeatTask(c, repeatCount)).collect(Collectors.toList()))
                        .stream()
                        .map(ForkJoinTask::join)
                        .flatMap(Collection::stream)
                        .collect(Collectors.toList());
            }
            return List.of(String.valueOf(chars.get(0)).repeat(Math.max(0, repeatCount)));
        }

    }

    public static void main(String[] args) {
        ForkJoinPool commonPool = ForkJoinPool.commonPool();
        RepeatTask task = new RepeatTask(List.of('a', 'b', 'c'), 4);
        commonPool.execute(task);
        System.out.println(task.join());
    }
}

结果是: [aaaa, bbbb, cccc]

相关问题