是否使用 invokeAll 或 submit - java Executor 服务
Whether to use invokeAll or 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(Collections of Callable)
ExecutorService executorService = Executors.newFixedThreadPool(5);
List<Future<String>> futures = executorService.invokeAll(myCallableList));
- 首选方式应该是什么?
- 与另一个相比,它们中的任何一个是否有任何缺点或性能影响?
编辑:
它们之间其实是有区别的。出于某种原因,invokeAll()
将为每个 future
生成调用 get()
。因此,它将等待任务完成,这就是为什么它可能会抛出 InterruptedException
(而 submit()
什么都不抛出)。
这是 invokeAll()
方法的 Javadoc:
Executes the given tasks, returning a list of Futures holding their status and results when all complete.
所以,这两种策略基本上都是一样的,但是如果你调用 invokeAll()
你会被阻塞,直到所有任务都完成。
原始(不完整)答案:
invokeAll()
方法正是用于此类情况。你绝对应该使用它。
你真的不需要实例化 List
,但是:
ExecutorService executorService = Executors.newFixedThreadPool(5);
List<Future<String>> futures = executorService.invokeAll(myCallableList));
这应该足够了,它看起来比第一个替代方案干净多了。
选项 1:您正在将任务提交给 ExecutorService
,并且您没有等待已提交给 ExecutorService
的所有任务完成]
选项 2 : 您正在等待已提交给 ExecutorService
.
的所有任务完成
What should be the preferred way?
根据应用要求,首选其中一个。
- 如果你不想在任务 submit() 到
ExecutorService
之后等待,更喜欢 Option 1
.
- 如果需要等待提交给
ExecutorService
的所有任务完成,首选Option 2
。
Is there any disadvantage or performance impact in any of them compared to the other one?
如果您的应用程序需要选项 2,与选项 1 不同,您必须等待提交给 ExecutorService
的所有任务完成。性能不是比较标准,因为两者都是为两个不同的目的而设计的。
还有一件更重要的事情:无论您喜欢什么选项,FutureTask
都会在任务执行期间吞下异常。你必须要小心。看看这个 SE 问题:Handling Exceptions for ThreadPoolExecutor
有了Java 8,你就多了一个选择:ExecutorCompletionService
A CompletionService that uses a supplied Executor to execute tasks. This class arranges that submitted tasks are, upon completion, placed on a queue accessible using take. The class is lightweight enough to be suitable for transient use when processing groups of tasks.
看看相关的SE问题:ExecutorCompletionService? Why do need one if we have invokeAll?
假设您有一个任务,其结果取决于独立可执行任务的数量。但是要完成初始任务,您只有有限的时间。就像它的一个 API 调用。
例如,您有 100 毫秒的时间来完成顶级任务,还有 10 个相关任务。为此,如果您在此处使用提交,代码将是什么样子。
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);
}
因此,如果每个子任务花费 exaclty 50ms 来完成上述代码段将花费 50 ms。
但是,如果每个子任务花费 1000 毫秒来完成,则上述任务将花费 100 * 10 = 1000 毫秒或 1 秒。这使得计算所有子任务的总时间小于 100 毫秒变得困难。
invokeAll 方法在这种情况下帮助我们
List<Futures> futures = service.invokeall(tasks, 100, TimeUnit.MILLISECONDS)
for(Future future: futures) {
if(!future.isCancelled()) {
results.add(future.get());
}
}
这样即使单个子任务花费的时间超过 100 毫秒,它所花费的最长时间也只有 100 毫秒。
我有一个场景,我必须为同一个可调用对象异步执行 5 个线程。据我了解,有两种选择:
1) 使用提交(可调用)
ExecutorService executorService = Executors.newFixedThreadPool(5);
List<Future<String>> futures = new ArrayList<>();
for(Callable callableItem: myCallableList){
futures.add(executorService.submit(callableItem));
}
2) 使用 invokeAll(Collections of Callable)
ExecutorService executorService = Executors.newFixedThreadPool(5);
List<Future<String>> futures = executorService.invokeAll(myCallableList));
- 首选方式应该是什么?
- 与另一个相比,它们中的任何一个是否有任何缺点或性能影响?
编辑:
它们之间其实是有区别的。出于某种原因,invokeAll()
将为每个 future
生成调用 get()
。因此,它将等待任务完成,这就是为什么它可能会抛出 InterruptedException
(而 submit()
什么都不抛出)。
这是 invokeAll()
方法的 Javadoc:
Executes the given tasks, returning a list of Futures holding their status and results when all complete.
所以,这两种策略基本上都是一样的,但是如果你调用 invokeAll()
你会被阻塞,直到所有任务都完成。
原始(不完整)答案:
invokeAll()
方法正是用于此类情况。你绝对应该使用它。
你真的不需要实例化 List
,但是:
ExecutorService executorService = Executors.newFixedThreadPool(5);
List<Future<String>> futures = executorService.invokeAll(myCallableList));
这应该足够了,它看起来比第一个替代方案干净多了。
选项 1:您正在将任务提交给 ExecutorService
,并且您没有等待已提交给 ExecutorService
的所有任务完成]
选项 2 : 您正在等待已提交给 ExecutorService
.
What should be the preferred way?
根据应用要求,首选其中一个。
- 如果你不想在任务 submit() 到
ExecutorService
之后等待,更喜欢Option 1
. - 如果需要等待提交给
ExecutorService
的所有任务完成,首选Option 2
。
Is there any disadvantage or performance impact in any of them compared to the other one?
如果您的应用程序需要选项 2,与选项 1 不同,您必须等待提交给 ExecutorService
的所有任务完成。性能不是比较标准,因为两者都是为两个不同的目的而设计的。
还有一件更重要的事情:无论您喜欢什么选项,FutureTask
都会在任务执行期间吞下异常。你必须要小心。看看这个 SE 问题:Handling Exceptions for ThreadPoolExecutor
有了Java 8,你就多了一个选择:ExecutorCompletionService
A CompletionService that uses a supplied Executor to execute tasks. This class arranges that submitted tasks are, upon completion, placed on a queue accessible using take. The class is lightweight enough to be suitable for transient use when processing groups of tasks.
看看相关的SE问题:ExecutorCompletionService? Why do need one if we have invokeAll?
假设您有一个任务,其结果取决于独立可执行任务的数量。但是要完成初始任务,您只有有限的时间。就像它的一个 API 调用。
例如,您有 100 毫秒的时间来完成顶级任务,还有 10 个相关任务。为此,如果您在此处使用提交,代码将是什么样子。
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);
}
因此,如果每个子任务花费 exaclty 50ms 来完成上述代码段将花费 50 ms。 但是,如果每个子任务花费 1000 毫秒来完成,则上述任务将花费 100 * 10 = 1000 毫秒或 1 秒。这使得计算所有子任务的总时间小于 100 毫秒变得困难。
invokeAll 方法在这种情况下帮助我们
List<Futures> futures = service.invokeall(tasks, 100, TimeUnit.MILLISECONDS)
for(Future future: futures) {
if(!future.isCancelled()) {
results.add(future.get());
}
}
这样即使单个子任务花费的时间超过 100 毫秒,它所花费的最长时间也只有 100 毫秒。