是使用 invokeAll 还是 submit - java Executor service

我有一个场景,我必须为相同的可调用异步执行5个线程。据我所知,有两种选择:

1) 使用提交(可调用)

ExecutorService executorService = Executors.newFixedThreadPool(5);
List<Future<String>> futures = new ArrayList<>();
for(Callable callableItem: myCallableList){
    futures.add(executorService.submit(callableItem));
}

2) 使用 invokeAll(可调用的集合)

ExecutorService executorService = Executors.newFixedThreadPool(5);
List<Future<String>> futures = executorService.invokeAll(myCallableList));
  1. 首选方式应该是什么?
  2. 与另一个相比,它们中的任何一个是否有任何缺点或性能影响?

答案 1

选项 1:您正在向 提交任务,而不是等待已完成已提交到 的所有任务ExecutorServiceExecutorService

选项 2:您正在等待已完成已提交到 的所有任务。ExecutorService

首选方式应该是什么?

根据应用要求,它们中的任何一个都是首选。

  1. 如果您不想在任务提交()后等待,则首选 。ExecutorServiceOption 1
  2. 如果需要等待已完成已提交到 的所有任务,请首选 。ExecutorServiceOption 2

与另一个相比,它们中的任何一个是否有任何缺点或性能影响?

如果您的应用程序需要选项 2,则必须等待提交到的所有任务完成,这与选项 1 不同。性能不是比较的标准,因为两者都是为两个不同的目的而设计的。ExecutorService

还有一件更重要的事情:无论你喜欢什么选项,都会在任务执行期间吞噬异常。你必须小心。看看这个 SE 问题:处理 ThreadPoolExecutor 的异常FutureTask

在Java 8中,您还有一个选择:ExecutorCompletionService。

使用提供的执行程序执行任务的完成服务。此类安排在完成后将提交的任务放在可使用 take 访问的队列中。该类足够轻量级,适合在处理任务组时进行瞬态使用。

看看相关的SE问题:执行者完成服务?如果我们有调用All,为什么需要一个?


答案 2

编辑:

它们之间实际上有区别。出于某种原因,将要求每个生产。因此,它将等待任务完成,这就是为什么它可能会抛出(而什么都不抛出)。invokeAll()get()futureInterruptedExceptionsubmit()

这是该方法的Javadoc:invokeAll()

执行给定的任务,返回一个 Future 列表,当所有任务完成时,保留其状态和结果。

因此,这两种策略基本上都是一样的,但是如果你打电话,你会被阻止,直到所有任务都完成。invokeAll()


原始(不完整)答案:

该方法完全适用于此类情况。你绝对应该使用它。invokeAll()

不过,您并不需要实例化它:List

ExecutorService executorService = Executors.newFixedThreadPool(5);
List<Future<String>> futures = executorService.invokeAll(myCallableList));

这应该足够了,它看起来比第一个替代方案干净得多。


推荐