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 месяца я нашел ответ на вопрос.
Это просто и легко использовать с ограниченным контролем. Вы можете использовать это
- Для запуска параллельных независимых задач без ожидания
- Дождитесь завершения всех ваших задач
Я предпочитаю этот, когда число Callable/Runnable
задач мало, а накапливание задач в неограниченной очереди не приводит к скоплению памяти и ухудшает производительность системы.
Скрывает детали низкого уровня ThreadPoolExecutor
, Не позволяет играть с другими параметрами (Bounded Queue, Rejection Handler
и т.д. для точной настройки производительности), как в ThreadPoolExectuor
,
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,
RejectedExecutionHandler handler)
Это дает вам больше контроля. Помимо установки минимального и максимального потоков, вы можете установить размер очереди и сделать BlockingQueue
ограничен.
Вы можете придумать свою собственную фабрику нитей, если вам нужны следующие функции
- Чтобы установить более описательное имя потока
- Чтобы установить статус демона потока
- Чтобы установить приоритет потока
Если ваше приложение ограничено числом ожидающих выполнения задач Runnable/Callable, вы будете использовать ограниченную очередь, задав максимальную емкость. Как только очередь достигает максимальной емкости, вы можете определить RejectionHandler. Java предоставляет четыре типа политик обработчика отклонений.
По умолчанию
ThreadPoolExecutor.AbortPolicy
обработчик генерирует исключительную ситуацию RejectedExecutionException при отклонении.В
ThreadPoolExecutor.CallerRunsPolicy
, поток, который вызывает execute, сам выполняет задачу. Это обеспечивает простой механизм управления с обратной связью, который замедляет скорость отправки новых задач.В
ThreadPoolExecutor.DiscardPolicy
задача, которая не может быть выполнена, просто отбрасывается.В
ThreadPoolExecutor.DiscardOldestPolicy
, если исполнитель не выключен, задача во главе рабочей очереди отбрасывается, а затем повторяется попытка выполнения (что может снова привести к сбою, в результате чего это повторяется).
CountDownLatch
: Эта структура позволяет потоку Java ждать, пока другой набор потоков не выполнит свои задачи.
Случаи применения:
Достижение максимального параллелизма: иногда мы хотим запустить несколько потоков одновременно для достижения максимального параллелизма
Дождитесь завершения N потоков перед началом выполнения другого блока кода
Обнаружение тупика.
Более подробная информация приведена в этой статье
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 - когда использовать какой?