Разница между Executor и ExecutorCompletionService в java

#java #multithreading #java.util.concurrent

#java #многопоточность #java.util.concurrent

Вопрос:

Как говорится в самом названии вопроса, в чем разница между классами Executors и ExecutorCompletionService в Java?

Я новичок в потоковой обработке, поэтому, если кто-нибудь может объяснить с помощью фрагмента кода, это очень помогло бы.

Ответ №1:

Предположим, у вас есть набор задач A, B, C, D, E , и вы хотите выполнить каждую из них асинхронно в an Executor и обработать результаты 1 на 1 по мере их завершения.

С помощью an Executor вы могли бы сделать это следующим образом:

 List<Future<?>> futures = new ArrayList<Future<?>>();
futures.add(executorService.submit(A));
futures.add(executorService.submit(B));
futures.add(executorService.submit(C));
futures.add(executorService.submit(D));
futures.add(executorService.submit(E));

//This loop must process the tasks in the order they were submitted: A, B, C, D, E
for (Future<?> future:futures) {
    ? result = future.get();
    // Some processing here
}
  

Проблема с этим методом заключается в том, что нет гарантии, что задача A завершится первой. Таким образом, возможно, что основной поток будет блокировать бездействие в ожидании A завершения задачи, когда он может обрабатывать результат другой задачи (скажем, задачи B ). Задержка обработки результатов может быть уменьшена с помощью ExecutorCompletionService .

 List<Future<?>> futures = new ArrayList<Future<?>>();
futures.add(executorCompletionService.submit(A));
futures.add(executorCompletionService.submit(B));
futures.add(executorCompletionService.submit(C));
futures.add(executorCompletionService.submit(D));
futures.add(executorCompletionService.submit(E));

//This for loop will process the tasks in the order they are completed,  
//regardless of submission order
for (int i=0; i<futures.size(); i  ) {
    ? result = executorCompletionService.take().get();
    // Some processing here
}
  

Таким образом, по сути, ExecutorCompletionService может использоваться для повышения эффективности, когда порядок обработки результатов задачи не имеет значения.

Однако следует отметить одну важную вещь. Реализация ExecutorCompletionService содержит очередь результатов. Если take or poll не вызывается для разрядки этой очереди, произойдет утечка памяти. Некоторые люди используют Future возвращаемый by submit для обработки результатов, и это неправильное использование.

Комментарии:

1. Большое спасибо, Тим, за вашу поддержку. Пример и объяснение предельно понятны.

2. Такой удивительный ответ и пока получил только 18 голосов. Это просто расстраивает меня. Этот младенец выглядит так мило в ваших руках.

Ответ №2:

An ExecutorCompletionService просто переносит и делегирует в обычный Executor и предлагает удобные методы для извлечения самых последних выполненных задач.

В api есть несколько примеров, которые должны помочь вам

http://download.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/ExecutorCompletionService.html