【问题标题】:Java ExecutorService (Thread Pool): Wait for the first task (Future) to finish and return immediatelyJava ExecutorService(线程池):等待第一个任务(Future)完成并立即返回
【发布时间】:2021-10-02 10:13:45
【问题描述】:

我需要同时调用几个(少于 30 个)REST API,并立即返回我从这些 API 调用中获得的第一个响应。

我实现了一个这样的方法:

public String fetchFastest(List<URL> urls) throws ExecutionException, InterruptedException {
    var executor = Executors.newFixedThreadPool(urls.size());

    var futures = new ArrayList<Future<String>>();
    urls.forEach(url -> {
        futures.add(
            executor.submit(() -> getResponse(url)) // performs a http request with timeout and returns the response (or null in the case of failure)
        );
    });

    var failed = new ArrayList<Future<String>>();
    while (failed.size() < futures.size()) {
        for(var f: futures) {
            if(f.isDone() && !failed.contains(f)) {
                if(f.get() == null) {
                    failed.add(f);
                }
                else {
                    executor.shutdownNow();
                    return f.get();
                }
            }
        }
    }

    throw new RuntimeException("No response.");
}

这种方法似乎奏效了。但是,鉴于此方法被频繁调用,并且创建线程池是一项昂贵的任务(我正在为每个方法调用创建一个),我想知道我是否可以以某种方式改进这种方法或找到其他更快的解决方案计算成本更低。

欢迎提出任何建议。提前谢谢你。

【问题讨论】:

  • 我会先取出线程池并共享一个,而不是每次都创建新的。您还需要添加工具来衡量性能,以便判断您所做的更改是否有效。
  • 这个方法会被并发调用吗?

标签: java multithreading concurrency


【解决方案1】:

首先,使用executor.invokeAny()。它将等到其中一项任务成功完成并取消其余的(因此将替换上面几乎所有的代码)。

关于在每个方法调用上创建线程池 - 有时这很有意义。但一开始,我会从公共池 (ForkJoinPool.commonPool()) 开始,或者创建自己的 static (==reusable) 池,并在分析性能后仅将其替换为 pool-per-method-call .

【讨论】:

    【解决方案2】:

    优化1: 创建一个静态的 FixedThreadPool。

    您可以通过以下方式确定线程池大小:(对 fetchFastest 方法的并发调用次数)x (urls.size())

    这样更好,因为 GC 不会清理您在每次函数调用时创建的线程池实例,并且静态的 FixedThreadPool 将被重新使用。

    优化2:中断不再需要的线程。

    收到第一个响应后中断所有其他线程。这将节省繁忙等待和计算时的 CPU 周期(如果有)。

    【讨论】:

      猜你喜欢
      • 2019-10-24
      • 2018-09-22
      • 2011-06-02
      • 2021-08-14
      • 1970-01-01
      • 1970-01-01
      • 2015-08-29
      • 2010-10-16
      相关资源
      最近更新 更多