【问题标题】:How to use supplyAsync of CompletableFuture to run the same method with multiple inputs each time?如何使用 CompletableFuture 的 supplyAsync 每次运行具有多个输入的相同方法?
【发布时间】:2021-05-25 20:28:56
【问题描述】:

我在下面的代码中创建了一个供应商,并使用 completableFuture 的 supplyAsync 方法在异步执行后调用另一个方法。

public void runParallelFunctions(MyInput myInput) {
    Supplier<Map<String, String>> taskSupplier = () -> {
        try {
            return invokeLambda("input1");
        } catch (Exception e) {
            System.out.println(e);
        }
        return new HashMap<>();
    };
    
    for (int i = 0; i < 5; i++) {
        CompletableFuture.supplyAsync(taskSupplier::get, executorService)
                         .thenAccept(this::printResultsFromParallelInvocations);
    }
    System.out.println("Doing other work....");
}

下面是我执行完成后调用的方法。

private void printResultsFromParallelInvocations(Map<String, String> result) {
        result.forEach((key, value) -> System.out.println(key + ": " + value));
}

在上面的代码中,如何调用 invokeLambda 方法并传递多个参数,如“input1”、“input2”等?我可以通过循环生成输入,但是如何与供应商一起使用某种列表,以便我可以为 supplyAsync 方法调用整个列表?我不能使用 runAsync 方法,因为我有一个需要调用 printResultsFromParallelInvocations 的返回值。我是期货和异步回调的新手,不胜感激。提前致谢。

【问题讨论】:

  • 无法理解问题。 ..供应商,以便我可以调用 supplyAsync 方法的整个列表:你能详细说明这部分吗?
  • 您为什么坚持创建一个供应商来做不同的事情?顺便说一句,使用taskSupplier::get 而不仅仅是taskSupplier 是没有意义的。对于前者,您将在每次迭代中创建一个新供应商,该供应商除了调用现有供应商的 get 方法外什么都不做。使用 for(int i = 0; i &lt; 5; i++) { String input = "input" + i; CompletableFuture.supplyAsync(() -&gt; invokeLambda(input), executorService) .thenAccept(this::printResultsFromParallelInvocations); } 之类的名称,但您应该更改误导性的方法名称 invokeLambda
  • @Holger 非常感谢您的回复。我没有意识到我每次都通过supplier.get 获得一个新的供应商,我的错。您可以将此作为答案发布吗?我会接受的。我还要重命名方法

标签: java multithreading asynchronous java-8 completable-future


【解决方案1】:

您不能创建单个Supplier&lt;Map&lt;String, String&gt;&gt; 并期望它在五次评估中表现不同。需要外部可变状态才能检测到评估是第 n 次评估,这同时与执行五个没有顺序的并发评估的想法相矛盾。

只需创建五个不同的供应商,例如

for(int i = 0; i < 5; i++) {
    String input = "input" + i;
    CompletableFuture.supplyAsync(() -> invokeLambda(input), executorService)
        .thenAccept(this::printResultsFromParallelInvocations);
}

在每次循环迭代中,lambda 表达式() -&gt; invokeLambda(input) 捕获input 的当前值并创建一个适当的Supplier 实例。

旁注:

  • 不要以invokeLambda 之类的技术方面命名方法,而是尝试表达它们的目的

  • 原始代码中的taskSupplier::get 是一个不必要的方法引用,因为它产生了一个Supplier 调用一个已经是Supplier 的对象上的方法。所以taskSupplier 可以直接传递给supplyAsync,如果每个评估的行为都相同的话。

【讨论】:

    【解决方案2】:

    您可以在循环内动态创建新的供应商。

    public static Supplier<Map<String, String>> supplierFunc(Object... args) {
        return () -> {
            try {
                return invokeLambda(args);
            } catch (Exception e) {
                System.out.println(e);
            }
            return new HashMap<>();
        };
    }
    
    public void runParallelFunctions(Object myInput) {
        for (int i = 0; i < 5; i++) {
            CompletableFuture.supplyAsync(supplierFunc("input1", "input2"), executorService)
                    .thenAccept(this::printResultsFromParallelInvocations);
        }
        System.out.println("Doing other work....");
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-01-27
      • 2015-10-07
      • 2011-12-26
      • 1970-01-01
      • 2017-08-03
      • 2013-02-03
      • 2021-09-14
      相关资源
      最近更新 更多