如果我们用一个ExecutorCompletionService我们可以提交一系列任务的Callable
S和得到的结果与交互CompletionService
的queue
。
但也有对invokeAll
的ExecutorService
一个接受Collection
任务,我们得到的名单Future
检索结果。
据我所知,有在使用一个以上的其他(但我们避免毫无益处for
循环使用invokeAll
,我们将不得不submit
任务的CompletionService
),基本上他们是有同样的想法细微的差别。
那么,为什么会有两种不同的方式提交一系列的任务? 难道我纠正性能明智的,他们是等价? 是否有一个比其它更适合的情况下? 我想不出之一。
使用ExecutorCompletionService.poll/take
,您收到的Future
S作为他们完成,在完成顺序(或多或少)。 使用ExecutorService.invokeAll
,你没有这个权力; 你要么块,直到全部完成后,或您指定在此之后,不完全被取消超时。
static class SleepingCallable implements Callable<String> {
final String name;
final long period;
SleepingCallable(final String name, final long period) {
this.name = name;
this.period = period;
}
public String call() {
try {
Thread.sleep(period);
} catch (InterruptedException ex) { }
return name;
}
}
现在,下面我将演示如何invokeAll
工作:
final ExecutorService pool = Executors.newFixedThreadPool(2);
final List<? extends Callable<String>> callables = Arrays.asList(
new SleepingCallable("quick", 500),
new SleepingCallable("slow", 5000));
try {
for (final Future<String> future : pool.invokeAll(callables)) {
System.out.println(future.get());
}
} catch (ExecutionException | InterruptedException ex) { }
pool.shutdown();
这将产生以下输出:
C:\dev\scrap>java CompletionExample
... after 5 s ...
quick
slow
使用CompletionService
,我们看到了一个不同的输出:
final ExecutorService pool = Executors.newFixedThreadPool(2);
final CompletionService<String> service = new ExecutorCompletionService<String>(pool);
final List<? extends Callable<String>> callables = Arrays.asList(
new SleepingCallable("slow", 5000),
new SleepingCallable("quick", 500));
for (final Callable<String> callable : callables) {
service.submit(callable);
}
pool.shutdown();
try {
while (!pool.isTerminated()) {
final Future<String> future = service.take();
System.out.println(future.get());
}
} catch (ExecutionException | InterruptedException ex) { }
这将产生以下输出:
C:\dev\scrap>java CompletionExample
... after 500 ms ...
quick
... after 5 s ...
slow
注意时间都是相对于程序开始,而不是以前的消息。
您可以同时找到完整的代码在这里 。
通过使用ExecutorCompletionService
,您可以立即得到每个作业完成时通知。 相比之下, ExecutorService.invokeAll(...)
等待您的所有任务返回的集合之前完成的Future
S:
// this waits until _all_ of the jobs complete
List<Future<Object>> futures = threadPool.invokeAll(...);
相反,当你使用一个ExecutorCompletionService
,您将能够尽快得到工作,因为每个人完成,它允许你(例如)送他们加工成另一个线程池,日志结果等。
ExecutorService threadPool = Executors.newFixedThreadPool(2);
ExecutorCompletionService<Result> compService
= new ExecutorCompletionService<Result>(threadPool);
for (MyJob job : jobs) {
compService.submit(job);
}
// shutdown the pool but the jobs submitted continue to run
threadPool.shutdown();
while (!threadPool.isTerminated()) {
// the take() blocks until any of the jobs complete
// this joins with the jobs in the order they _finish_
Future<Result> future = compService.take();
// this get() won't block
Result result = future.get();
// you can then put the result in some other thread pool or something
// to immediately start processing it
someOtherThreadPool.submit(new SomeNewJob(result));
}
我还没有过实际使用ExecutorCompletionService,但我想在那里,当你想收到的已完成任务的期货完成顺序,这可能会比“正常”的ExecutorService更有用的是这种情况。 的invokeAll有了,你只会得到可以在任何给定的时间包含不完整的,已完成任务的混合列表。
只考虑结果的顺序进行比较:
当我们使用CompletionService
只要提交完成结果的工作将被推到队列(完成顺序)。 然后提交的作业,并返回结果的顺序是不一样多。 所以,如果你关心哪些任务得到执行使用该命令CompletionService
凡为invokeAll
返回表示由迭代器给定的任务列表,每个已完成生产任务,在同一顺序期货的列表。