вызов ExecutorService.shutDown () в Java - PullRequest
7 голосов
/ 27 февраля 2012

Я начинаю изучать класс ExecutorService.Документация (и учебные пособия онлайн) говорят всегда вызывать ExecutorService.shutDown () для восстановления ресурсов.однако в документации также сказано, что после вызова shutDown () новые задачи не принимаются.Итак, мой вопрос: всегда ли мне нужно создавать экземпляр нового ExecutorService всякий раз, когда мне нужно распараллелить обработку данных?

сейчас у меня есть список объектов Callable, и я делаю следующее.

public void someMethod() {
 List<OuterCallable> outerCallables = getOuterCallables();
 ExecutorService executor = Executor.newFixedThreadPool(NUM_CPUS);
 executor.invokeAll(tasks);
 executor.shutDown();
}

однако мой OuterCallable также разделяет данные или выполняет обработку данных параллельно, используя InnerCallable.

public class OuterCallable implements Callable<Long> {
 public Long call() throws Exception {
  long result = 0L;

  List<InnerCallable> innerCallables = getInnerCallables();
  ExecutorServices executor = Executor.newFixedThreadPool(NUM_CPUS);
  executor.invokeAll(tasks);
  executor.shutDown();

  return result;
 }
}    

Я не могу вспомнить, было ли это для ExecutorService или подхода Fork / Join, но я помню документацию и руководства, в которых говорилось, что фактическая параллельная процедура для манипулирования данными не должна включать операции ввода-вывода, и все должно бытьсделано в памяти.однако в моем InnerCallable я фактически выполняю вызовы JDBC (здесь не показаны).

в конечном счете, то, как я использую ExecutorService, работает, но у меня все еще есть проблемы.

  1. мой подход выше хорошей практики программирования с использованием ExecutorService?
  2. должен ли я использовать одноэлементный экземпляр ExecutorService?
  3. должен ли я не только избегать операций ввода-вывода внутри моих параллельных методов, но также и вызовов JDBC?

В качестве последней проблемы я пытался немного изучить Fork / Join vs ExecutorService.я наткнулся на статью, которая полностью взорвала API / классы Fork / Join.стоит ли изучать Fork / Join?Я видел несколько статей о стековом потоке и в других местах, где тесты используются для сравнения Fork / Join и ExecutorService, и есть графики, показывающие лучшее использование ЦП Fork / Join против ExecutorService (через диспетчер задач Windows).Тем не менее, когда я использую ExecutorService (JDK 1.7.x), загрузка моего процессора составляет макс.улучшен ли ExecutorService с последней версией JDK?

любая помощь / руководство приветствуется.

1 Ответ

4 голосов
/ 27 февраля 2012

Вы должны добавить awaitTermination вызовы, потому что shutDown возвращается, не дожидаясь завершения Callables. Кроме этого,

  1. Есть ли у вас OuterCallable последовательные зависимости? Если это так, ваш подход в порядке, но использование ForkJoinPool было бы предпочтительнее, потому что оно будет поддерживать низкое количество рабочих потоков. Если нет, то было бы лучше отправить большую сплющенную коллекцию Callable с одному Executor.
  2. Только если вы хотите использовать ExecutorService в нескольких различных подпрограммах и хотите избежать его передачи. Если он используется только в someMethod, он может быть создан там же, как и вы.
  3. Вам следует избегать процедур ввода-вывода, выполнение которых займет много времени. Если ваш ExecutorService имеет 4 рабочих потока и все они блокируют ввод / вывод, JVM вообще не будет использовать ЦП, даже если другие Callables могут ожидать выполнения работы, интенсивно использующей ЦП. Несколько вызовов JDBC в порядке, если запросы не занимают много времени.
...