是否使用invokeAll或submit - java Executor服务

时间:2015-12-23 17:10:45

标签: java concurrency executorservice java.util.concurrent

我有一个场景,我必须为同一个callable异步执行5个线程。据我了解,有两种选择:

1)使用submit(Callable)

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

2)使用invokeAll(Callable of Collelable)

ExecutorService executorService = Executors.newFixedThreadPool(5);
List<Future<String>> futures = executorService.invokeAll(myCallableList));
  1. 什么应该是首选方式?
  2. 与其他产品相比,是否存在任何劣势或性能影响?

3 个答案:

答案 0 :(得分:12)

选项1 :您正在将任务提交至ExecutorService,而您并未等待已完成所有已提交至ExecutorService的任务

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

  

什么应该是首选方式?

根据应用要求,首选其中任何一种。

  1. 如果您在任务提交()之后不等待ExecutorService,请选择Option 1
  2. 如果您需要等待已完成已提交至ExecutorService的所有任务,请选择Option 2
  3.   

    与其他产品相比,它们中是否存在任何不利或性能影响?

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

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

    使用Java 8,您还有一个选项:ExecutorCompletionService

      

    CompletionService ,它使用提供的Executor执行任务。该类安排提交的任务在完成后放置在可使用take访问的队列中。该类足够轻巧,适合在处理任务组时暂时使用。

    查看相关的SE问题:ExecutorCompletionService? Why do need one if we have invokeAll?

答案 1 :(得分:3)

编辑:

它们之间确实存在差异。出于某种原因,invokeAll()会为生成的每个get()调用future。因此,它将等待任务完成,这就是为什么它可能抛出InterruptedException(而submit()不抛出任何东西)。

这是invokeAll()方法的Javadoc:

  

执行给定的任务,返回持有状态的结果列表,并在完成所有完成后返回

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

原始(不完整)答案:

invokeAll()方法适用于这些情况。你绝对应该使用它。

但实际上并不需要实例化List

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

这应该足够了,它看起来比第一种选择更清洁。

答案 2 :(得分:1)

假设您有一个任务,其结果取决于独立可执行任务的数量。但是对于完成初始任务,您只有有限的时间。就像它的API调用一样。

因此,例如,您需要100毫秒才能完成顶级任务,并且还有10个相关任务。为此,如果你在这里使用提交代码将如何。

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="file" name="file" multiple class="idProjectTitle" />

<input type="text" id="hdProjectTitle" name="hdProjectTitle" />

因此,如果每个子任务花费50ms来完成上述代码,则需要50 ms。 但是如果每个子任务花费1000毫秒来完成上述将花费100 * 10 = 1000毫秒或1秒。这使得所有子任务的总时间难以计算小于100毫秒。

invokeAll方法可以帮助我们实现这种情况

List<Callable> tasks = []// assume contains sub tasks
List<Future> futures = [] 
for(Callable task: tasks) {
   futures.add(service.submit(task));
}

for(Future futute: futures) {
    future.get(100, TimeUnit.MILLISECONDS);
}

这样,即使个别子任务占用超过100毫秒,它所需的最长时间也只需100毫秒。