Используя 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
Обратите внимание, что время указано относительно запуска программы, а не предыдущего сообщения.
Полный код можно найти здесь.
person
obataku
schedule
08.08.2012