Java Форк / Объединить пул, ExecutorService и CountDownLatch

У нас есть три разных метода многопоточности в Java - Fork/Join pool, Executor Service и CountDownLatch

Fork/Join join ( http://www.javacodegeeks.com/2011/02/java-forkjoin-parallel-programming.html)

Инфраструктура Fork/Join разработана для упрощения распараллеливания алгоритмов "разделяй и властвуй". Этот тип алгоритмов идеально подходит для задач, которые можно разделить на две или более подзадач одного типа. Они используют рекурсию, чтобы разбить проблему на простые задачи, пока они не станут достаточно простыми для непосредственного решения. Решения подзадач затем объединяются, чтобы дать решение исходной проблемы

ExecutorService - это интерфейс, который расширяет класс Executor и представляет асинхронное выполнение. Он предоставляет нам механизмы для управления завершением и выявления хода выполнения асинхронных задач.

invokeAll (): выполняет заданные задачи, возвращая список фьючерсов с их статусом и результатами, когда все выполнено. Future.isDone() имеет значение true для каждого элемента возвращаемого списка.

CountDownLatch:( http://examples.javacodegeeks.com/core-java/util/concurrent/countdownlatch-concurrent/java-util-concurrent-countdownlatch-example/)

CountDownLatch используется в синхронизации, чтобы позволить одному или нескольким потокам дождаться завершения набора операций, выполняемых в других потоках.

Мое предположение:

В обеих этих альтернативах конечный результат будет известен только после завершения всех задач / потоков.

Эти три альтернативы дополняют или дополняют друг друга?

1 ответ

Решение

После исследования различных многопоточных сред за последние 3 месяца я нашел ответ на вопрос.

ExecutorService

Это просто и легко использовать с ограниченным контролем. Вы можете использовать это

  1. Для запуска параллельных независимых задач без ожидания
  2. Дождитесь завершения всех ваших задач

Я предпочитаю этот, когда число Callable/Runnable задач мало, а накапливание задач в неограниченной очереди не приводит к скоплению памяти и ухудшает производительность системы.

Скрывает детали низкого уровня ThreadPoolExecutor, Не позволяет играть с другими параметрами (Bounded Queue, Rejection Handler и т.д. для точной настройки производительности), как в ThreadPoolExectuor,

ThreadPoolExecutor

ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, 
TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,
RejectedExecutionHandler handler)

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

Вы можете придумать свою собственную фабрику нитей, если вам нужны следующие функции

  1. Чтобы установить более описательное имя потока
  2. Чтобы установить статус демона потока
  3. Чтобы установить приоритет потока

Если ваше приложение ограничено числом ожидающих выполнения задач Runnable/Callable, вы будете использовать ограниченную очередь, задав максимальную емкость. Как только очередь достигает максимальной емкости, вы можете определить RejectionHandler. Java предоставляет четыре типа политик обработчика отклонений.

  1. По умолчанию ThreadPoolExecutor.AbortPolicyобработчик генерирует исключительную ситуацию RejectedExecutionException при отклонении.

  2. В ThreadPoolExecutor.CallerRunsPolicy, поток, который вызывает execute, сам выполняет задачу. Это обеспечивает простой механизм управления с обратной связью, который замедляет скорость отправки новых задач.

  3. В ThreadPoolExecutor.DiscardPolicy задача, которая не может быть выполнена, просто отбрасывается.

  4. В ThreadPoolExecutor.DiscardOldestPolicy, если исполнитель не выключен, задача во главе рабочей очереди отбрасывается, а затем повторяется попытка выполнения (что может снова привести к сбою, в результате чего это повторяется).

CountDownLatch

CountDownLatch: Эта структура позволяет потоку Java ждать, пока другой набор потоков не выполнит свои задачи.

Случаи применения:

  1. Достижение максимального параллелизма: иногда мы хотим запустить несколько потоков одновременно для достижения максимального параллелизма

  2. Дождитесь завершения N потоков перед началом выполнения другого блока кода

  3. Обнаружение тупика.

Более подробная информация приведена в этой статье

ForkJoinPool

ForkJoinPool похож на Java ExecutorService, но с одним отличием. ForkJoinPool позволяет задачам разделить свою работу на более мелкие задачи, которые затем передаются в ForkJoinPool. Кража задач происходит в ForkJoinPool, когда свободные рабочие потоки крадут задачи из очереди занятых рабочих потоков.

public ForkJoinPool(int parallelism,
            ForkJoinPool.ForkJoinWorkerThreadFactory factory,
            Thread.UncaughtExceptionHandler handler,
            boolean asyncMode)
Creates a ForkJoinPool with the given parameters.

Параметры:

параллелизм - уровень параллелизма. Для значения по умолчанию используйте Runtime.availableProcessors(),

фабрика - фабрика для создания новых ниток. Для значения по умолчанию используйте defaultForkJoinWorkerThreadFactory.

handler - обработчик для внутренних рабочих потоков, которые завершаются из-за неисправимых ошибок

asyncMode - если true, устанавливает локальный режим планирования "первым пришел - первым вышел" для разветвленных задач, которые никогда не объединяются.

По основному запросу:

Ты можешь использовать ExecutorService.invokeAll() или же CountDownLatch рамки или ForkJoinPool , Все эти платформы дополняют друг друга, варьируя степень детализации, чтобы контролировать выполнение задач от высокого уровня до низкого уровня.

РЕДАКТИРОВАТЬ:

Посмотрите на связанные вопросы SE:

Каковы преимущества использования ExecutorService?

Java Fork/Join vs ExecutorService - когда использовать какой?

Другие вопросы по тегам