Каковы преимущества использования ExecutorService? - PullRequest
41 голосов
/ 21 октября 2010

В чем преимущество использования ExecutorService перед запущенными потоками, передающими Runnable в конструктор Thread?

Ответы [ 8 ]

40 голосов
/ 21 октября 2010

ExecutorService абстрагирует многие сложности, связанные с абстракциями более низкого уровня, такими как raw Thread. Он предоставляет механизмы для безопасного запуска, закрытия, отправки, выполнения и блокировки при успешном или внезапном завершении задач (выражается как Runnable или Callable).

С JCiP , раздел 6.2, прямо изо рта лошади:

Executor может быть простым интерфейсом, но он служит основой для гибкой и мощной структуры для асинхронного выполнения задач, которая поддерживает широкий спектр политик выполнения задач. Он обеспечивает стандартные средства отделения отправки задачи от выполнения задачи , описывая задачи как Runnable. Реализации Executor также предоставляют поддержку жизненного цикла и ловушки для добавления сбора статистики, управления приложениями и мониторинга. ... Использование Executor, как правило, является самым простым способом реализации дизайна «производитель-потребитель» в вашем приложении.

Вместо того, чтобы тратить свое время на реализацию (часто неправильно и с большими усилиями) базовой инфраструктуры для параллелизма, инфраструктура j.u.concurrent позволяет вместо этого сосредоточиться на структурировании задач, зависимостей и потенциального параллелизма. Для большого количества параллельных приложений легко определить и использовать границы задач и использовать j.u.c, что позволяет вам сосредоточиться на гораздо меньшем подмножестве реальных задач параллелизма, которые могут потребовать более специализированных решений.

Кроме того, несмотря на шаблонный внешний вид, страница Oracle API , обобщающая утилиты параллелизма , содержит несколько действительно веских аргументов в пользу их использования, не в последнюю очередь:

Разработчики, скорее всего, уже понять стандартную библиотеку классы, поэтому нет необходимости учиться API и поведение ad-hoc параллельные компоненты. Дополнительно, параллельные приложения далеко проще отлаживать, когда они построены на надежных, хорошо протестированных компонентах.

Этот вопрос о SO спрашивает о хорошей книге, на которую немедленным ответом является JCiP. Если вы еще этого не сделали, получите себе копию. Представленный здесь комплексный подход к параллелизму выходит далеко за рамки этого вопроса и в долгосрочной перспективе избавит вас от душевных страданий.

18 голосов
/ 21 октября 2010

Я вижу преимущество в управлении / планировании нескольких потоков.С ExecutorService вам не нужно писать собственный менеджер потоков, который может быть подвержен ошибкам.Это особенно полезно, если ваша программа должна запускать несколько потоков одновременно.Например, если вы хотите выполнить два потока одновременно, вы можете легко сделать это следующим образом:

ExecutorService exec = Executors.newFixedThreadPool(2);

exec.execute(new Runnable() {
  public void run() {
    System.out.println("Hello world");
  }
});

exec.shutdown();

Пример может быть тривиальным, но попробуйте подумать, что строка «hello world» состоит изоперация, и вы хотите, чтобы эта операция выполнялась в нескольких потоках одновременно, чтобы улучшить производительность вашей программы.Это только один пример, все еще есть много случаев, когда вы хотите запланировать или запустить несколько потоков и использовать ExecutorService в качестве диспетчера потоков.ExecutorService.

10 голосов
/ 19 декабря 2015

Следующие ограничения по сравнению с традиционным потоком преодолены платформой Executor (встроенной структурой пула потоков).

  • Плохое управление ресурсами Т.е. оно продолжает создавать новый ресурс для каждого запроса. Нет ограничений на создание ресурса. Используя платформу Executor, мы можем повторно использовать существующие ресурсы и ограничить их создание.
  • Not Robust : Если мы продолжим создавать новый поток, мы получим исключение StackOverflowException, следовательно, наша JVM потерпит крах.
  • Накладные расходы Создание времени : Для каждого запроса нам нужно создать новый ресурс. На создание нового ресурса уходит много времени. создание темы> задача. Используя фреймворк Executor, мы можем получить встроенный пул потоков.

Преимущества пула потоков

  • Использование пула потоков сокращает время ответа, избегая создания потоков во время обработки запросов или задач.

  • Использование Thread Pool позволяет вам изменять политику выполнения по мере необходимости. Вы можете перейти из одного потока в несколько потоков, просто заменив реализацию ExecutorService.

  • Пул потоков в приложении Java повышает стабильность системы, создавая сконфигурированное количество потоков, определяемое исходя из загрузки системы и доступного ресурса.

  • Thread Pool освобождает разработчика приложений от управления потоками и позволяет сосредоточиться на бизнес-логике.

Источник

7 голосов
/ 01 июля 2013

Ниже приведены некоторые преимущества:

  1. Служба исполнителя управляет потоком асинхронным способом
  2. Используйте функцию callable для получения результата возврата после завершения потока.
  3. Управление выделениемработа для освобождения потока и перепродажи завершенная работа из потока для автоматического назначения новой работы
  4. fork - объединение инфраструктуры для параллельной обработки
  5. улучшенная связь между потоками
  6. invokeAll и invokeAny дают больше контролязапускать один или все потоки одновременно
  7. shutdown предоставляет возможность завершения всей назначенной потоку работы
  8. Службы Scheduled Executor Services предоставляют методы для создания повторяющихся вызовов runnables и callables. Надеюсь, это поможет вам
2 голосов
/ 27 февраля 2016

Неужели так дорого создавать новый поток?

В качестве теста я только что создал 60 000 потоков с Runnable с пустыми методами run().После создания каждого потока я немедленно вызвал его метод start(..).Это заняло около 30 секунд интенсивной работы процессора.Подобные эксперименты были проведены в ответ на этот вопрос .Суть в том, что если потоки не завершаются немедленно и накапливается большое количество активных потоков (несколько тысяч), то возникнут проблемы: (1) у каждого потока есть стек, поэтому у вас не хватит памяти, (2) может быть ограничение на количество потоков на процесс, налагаемое ОС, но необязательно, кажется .

Итак, насколько я вижу, еслимы говорим о запуске, скажем, 10 потоков в секунду, и все они заканчиваются быстрее, чем запускаются новые, и мы можем гарантировать, что эта скорость не будет превышена слишком сильно, тогда ExecutorService не предлагает никаких конкретных преимуществ в видимой производительностиили стабильность.(Хотя это все же может сделать его более удобным или читабельным для выражения определенных идей параллелизма в коде.) С другой стороны, если вы можете планировать сотни или тысячи задач в секунду, на выполнение которых требуется время, вы можете столкнуться с большими проблемами.сразу.Это может произойти неожиданно, например, если вы создаете потоки в ответ на запросы к серверу, и наблюдается интенсивность запросов, которые получает ваш сервер.Но, например, один поток в ответ на каждое событие пользовательского ввода (нажатие клавиши, движение мыши), кажется, прекрасно, если задачи кратки.

1 голос
/ 11 июня 2015

ExecutorService также предоставляет доступ к FutureTask, который вернет вызывающему классу результаты фоновой задачи после завершения.В случае реализации Callable

public class TaskOne implements Callable<String> {

@Override
public String call() throws Exception {
    String message = "Task One here. . .";
    return message;
    }
}

public class TaskTwo implements Callable<String> {

@Override
public String call() throws Exception {
    String message = "Task Two here . . . ";
    return message;
    }
}

// from the calling class

ExecutorService service = Executors.newFixedThreadPool(2);
    // set of Callable types
    Set<Callable<String>>callables = new HashSet<Callable<String>>();
    // add tasks to Set
    callables.add(new TaskOne());
    callables.add(new TaskTwo());
    // list of Future<String> types stores the result of invokeAll()
    List<Future<String>>futures = service.invokeAll(callables);
    // iterate through the list and print results from get();
    for(Future<String>future : futures) {
        System.out.println(future.get());
    }
0 голосов
/ 18 июня 2018

Создание большого количества потоков без ограничения максимального порога может привести к нехватке памяти в приложении.Из-за этого создание ThreadPool является гораздо лучшим решением.Используя ThreadPool, мы можем ограничить количество потоков, которые могут быть объединены и использованы повторно.

Фреймворк Executors облегчает процесс создания пулов потоков в Java.Класс Executors обеспечивает простую реализацию ExecutorService с использованием ThreadPoolExecutor.

Источник:

Что такое Executors Framework

0 голосов
/ 13 февраля 2015

До версии Java 1.5, Thread / Runnable был разработан для двух отдельных сервисов

  1. Единица работы
  2. Выполнение этой единицы работы

ExecutorService разъединяет эти две службы, определяя Runnable / Callable как единицу работы и Executor как механизм для выполнения (с жизненным циклом) единицы работы

...