【问题标题】:Calling an API asynchronously java异步调用 API java
【发布时间】:2020-06-10 13:47:54
【问题描述】:

我正在遍历一个 ID 列表并进行查找以获取对象。我是多线程新手,有没有办法在不使用并行流的情况下处理这个问题?

private List<MyObject> lookupById(List<String> ids) {
  List<MyObject> myObjs = new ArrayList<>();

  for(String id : ids) {
    myObjs.add(apiService.lookUp(id));
  }

  return myObjs;
}

【问题讨论】:

  • 为什么不使用并行流?
  • 并行流能否很好地扩展可能最终需要一段时间的事情?仅仅因为我正在调用数据库,我认为并行流在这些情况下会很危险

标签: java multithreading asynchronous


【解决方案1】:

这就是我的想法:

private List<MyObject> lookupById(List<String> ids) {

    List<MyObject> myObjs = Collections.synchronizedList(new ArrayList<>());

    CountDownLatch countDownLatch = new CountDownLatch(ids.size());
    ids.forEach(e -> {

        new Thread(() -> {

            myObjs.add(apiService.lookUp(e));
            countDownLatch.countDown();

        }).start();

    });

    try{
        countDownLatch.await();
    }catch(Exception ignored){}

    return myObjs;

}

也可以有其他方式。

【讨论】:

  • 没有加入什么的,你只是要返回一个空列表?
  • @matt 加入?它不会返回一个空列表。 myObjs.add(apiService.lookUp(e));Thread 实现中。
  • 是的,但您不知道“查找”需要多长时间。创建一个线程并调用 start 可以非常快。因此可以在添加任何项目之前返回 myObjs。这也意味着它将在返回后进行修改。
  • @matt 我更新了它。但是现在,我不确定这是否是最好的方法。因为可以以无限循环结束。这取决于apiService.lookUp 中发生的事情。不过谢谢你的观察。我省略了。
  • @Spider 是的,您不需要为每个任务创建一个线程,您可以让每个线程处理多个任务。如果您使用执行器服务,它会为您管理线程。 Executors 是一个方便的类,用于创建具有不同选项的执行器服务。
【解决方案2】:

这是一种使用执行器服务的方法。

ExecutorService pool = Executors.newFixedThreadPool(N);
List<Future<MyObject>> futures = ids.stream().map( 
                                     pool.sumbit( 
                                         id->apiService.lookUp(id) 
                                     ).collect( Collectors.toList() );
List<MyObject> myObjs = futures.stream().map( f -> { 
                                                     try { 
                                                         f.get();
                                                     } catch (Exception e){         
                                                         return null;
                                                     }
                                             ).collect( Collectors.toList());

这会保持列表的顺序。否则线程版本可能就足够了。我不知道你为什么不只使用并行流。

与公认的解决方案相比,这具有优势。

  • 列表顺序相同。
  • 如果出现异常,则会添加 null 而不是永远不会完成。
  • 不会创建无限数量的线程。只创建应该是一个合理数字的“N”。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-01-30
    • 2022-01-19
    • 2017-10-28
    • 2020-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-29
    相关资源
    最近更新 更多