【问题标题】:Get result of completablefuture获取 CompletableFuture 的结果
【发布时间】:2020-03-10 06:04:30
【问题描述】:

我正在使用 completablefuture 从 springboot 应用程序中的异步线程返回。我的实现如下。据我了解,应该为列表中的每个项目启动一个新线程,并且应该并行处理。我知道 .get 会阻止执行,但由于它是并行运行的,我仍然看不到性能有任何改进。请在下面提出任何建议以提高性能?

ServiceA.java

@Autowired
ServiceB serviceb;


public List<String> getNames(List<Item> items) {
List<CompletableFuture<String>> list = new ArrayList<>();
List<String> returnList = new ArrayList<>();
for( Item item: items) {
  CompletableFuture<String> getItemName = serviceb.doProcess(item);
  list.add(getItemName):
}

for( CompletableFuture name : list) {
 returnList.add(name.get());
}
return returnList;
}

ServiceB.java

Class ServiceB {
@Async
Public CompletableFuture<String> doProcess(Item item)
{
   //do process
}

【问题讨论】:

    标签: java multithreading spring-boot asynchronous parallel-processing


    【解决方案1】:

    您可以致电allOf 等待所有结果。这将等待所有 CompletableFuture 完成。

            List<String> returnList = new ArrayList<>(items.size());
            CompletableFuture<String>[] tasks = items.stream()
                .map(value-> serviceb.doProcess(value).thenApply(returnList::add))
                .toArray(CompletableFuture[]::new);
            // wait for all tasks to finish
            CompletableFuture.allOf(tasks).get(50, TimeUnit.SECONDS);
            // return the results
            return returnList;
    

    第二种解决方案是使用像发布者/订阅者模式(Spring WebFluxJavaRx)这样的被动方法。这样,您的应用程序将很少/没有等待操作。但这会影响您的应用程序架构。

    一条建议: 要创建CompletableFuture,请使用带有ExecutorService 的构造函数,以便检查线程数并控制正在运行的线程或应用程序何时关闭。

    【讨论】:

    • 我在上面试过了。但我看到流程正在继续,无需等待任务完成。我可以看到响应返回给调用者,但之后线程仍在运行,这意味着它没有等待任务完成。跨度>
    • 我做了一个 .join() 。改变了这个“CompletableFuture.allOf(tasks).get(50, TimeUnit.SECONDS);”到 "CompletableFuture.allOf(tasks).get(50, TimeUnit.SECONDS).join()" 成功了。感谢您的帮助
    【解决方案2】:

    get() 肯定不会成功,因为它会阻塞执行的主线程以从异步线程中获取结果。更好的选择是相应地使用回调方法(thenApply() 等),以便让主线程继续工作。

    【讨论】:

    • 感谢您的回复。不确定 thenApply() 它是做什么的。一定会探索这个选项。
    【解决方案3】:

    您可以使用thenAccept 将项目添加到列表中。

    List<String> list = new CopyOnWriteArrayList<>();
    CompletableFuture.allOf(
        Stream.of(items).map(
            i -> CompletableFuture.supplyAsync(i).thenAccept(list::add)
        ).toArray(CompletableFuture[]::new)
    ).get(10, SECONDS);
    
    return list;
    

    【讨论】:

    • 感谢您的回复。这看起来和我已经实现的一样。但是你介意解释一下“CopyOnWriteArrayList”吗?为什么不在这里简单的ArrayList?
    • @JingJong 您同时添加到列表中,因此您需要一个线程安全的列表。 ArrayList 不是。
    • 有道理。谢谢。
    猜你喜欢
    • 2015-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-04
    • 1970-01-01
    • 1970-01-01
    • 2017-09-09
    相关资源
    最近更新 更多