32

Java 5 ввела поддержку для выполнения асинхронной задачи пулом потоков в форме инфраструктуры Executor, чье сердце является пулом потоков, реализованным java.util.concurrent.ThreadPoolExecutor. Java 7 добавила альтернативный пул потоков в виде java.util.concurrent.ForkJoinPool.В чем преимущество Java-5 ThreadPoolExecutor над Java-7 ForkJoinPool?

Рассматривая свой API, ForkJoinPool обеспечивает надстройку функциональности ThreadPoolExecutor в стандартных сценариях (хотя, строго говоря, ThreadPoolExecutor предлагает больше возможностей для настройки, чем ForkJoinPool). Добавляя к этому замечание, что задачи fork/join кажутся более быстрыми (возможно, из-за планировщика кражи работы), нужно определенно меньше потоков (из-за операции без блокировки соединения), может возникнуть впечатление, что ThreadPoolExecutor был заменен от ForkJoinPool.

Но это действительно правильно? Весь материал, я прочитал, кажется, подвести итог довольно смутное различие между этими двумя типами пулов потоков:

  • ForkJoinPool для многих, в зависимости, задачи сгенерированные, короткие, вряд ли когда-либо блокировки (т.е. требующих интенсивных вычислений) задачи
  • ThreadPoolExecutor для нескольких независимых, внешне сгенерированных, длинных, иногда блокирования задач

является ли это различие правильно вообще? Можем ли мы сказать что-то более конкретное об этом?

ответ

14

ThreadPool (TP) и ForkJoinPool (FJ) предназначены для различных вариантов использования. Основное различие заключается в количестве очередей, используемых различными исполнителями, которые решают, какие проблемы лучше подходят для любого исполнителя.

Исполнитель FJ имеет n (один уровень параллелизма) отдельных параллельных очередей (deques), в то время как исполнитель TP имеет только одну параллельную очередь (эти очереди/запросы могут быть пользовательскими реализациями, не соответствующими API-интерфейсам JDK Collections). В результате в сценариях, где вы создаете большое количество (обычно относительно коротких) задач, исполнитель FJ будет работать лучше, поскольку независимые очереди минимизируют параллельные операции, а нечастые перехваты помогут с балансировкой нагрузки. В TP из-за одиночной очереди будут выполняться параллельные операции каждый раз, когда работа будет отменена, и она будет действовать как относительное узкое место и ограничить производительность.

В отличие от этого, если относительно меньше длительных задач одиночная очередь в TP больше не является узким местом для производительности. Тем не менее, n-независимые очереди и относительно частые попытки кражи работы теперь станут узким местом в FJ, так как может быть много тщетных попыток украсть работу, которая добавит накладные расходы.

Кроме того, алгоритм поиска работы в FJ предполагает, что (более старые) задачи, украденные из deque, будут производить достаточно параллельных задач для уменьшения количества краж. Например. в quicksort или mergesort, где более старые задачи равны более крупным массивам, эти задачи будут генерировать больше задач и держать очередь непустой и уменьшать количество общих краж. Если это не так в данном приложении, то частые попытки кражи снова становятся узким местом. Это также было отмечено в Javadoc для ForkJoinPool:

этот класс предоставляет методы проверки состояния (например, getStealCount()) , которые предназначены для оказания помощи в разработке, настройке и мониторингу вилка/присоединиться к приложениям.

+0

Я думаю, что fork join рассматривает рекурсивный случай по-разному, они должны украсть более новые задачи в рекурсивных случаях. – user

+0

@user В соответствии с «Рамкой вилки/объединения Java» Дуга Ли: Когда рабочий поток не имеет локальных задач для запуска, он пытается взять («украсть») задачу у другого произвольно выбранного работника, используя FIFO (старейший первый) правило. – shams

+3

Следует добавить, что «deque», о котором говорят многие люди, не является известной реализацией [Deque] (http://docs.oracle.com/javase/7/docs/api/java/util/Deque.html) интерфейс. Это массив. См. Исходный код 'ForkJoinWorkerThread'. У него есть поле для доступа по умолчанию 'ForkJoinTask [] queue'. –

9

Рекомендуемая литература http://gee.cs.oswego.edu/dl/jsr166/dist/docs/ Из документов для ForkJoinPool:

ForkJoinPool отличается от других видов ExecutorService в основном силу использования работы кражи: все нити в попытке пула для поиска и выполнения задач отправленные в пул и/или созданные другими активными задачами (в конечном итоге блокирование ожидания работы, если оно не существует). Это позволяет эффективно обрабатывать, когда большинство задач порождают другие подзадачи (как и большинство ForkJoinTasks), а также когда многие небольшие задачи составляют , отправленные в пул от внешних клиентов. Особенно, если при установке asyncMode на true в конструкторах, ForkJoinPools может также быть , подходящим для использования с задачами в стиле событий, которые никогда не соединяются.

Предназначен для параллельного выполнения, поскольку служба-исполнитель допускает параллельное выполнение, и есть разница. См. this и this.

Рамка fork join также позволяет выполнять кражу работы (использование Deque).

This article хорошее чтение.

+2

Возможно, вы могли бы сказать, в чем состоит эта разница. Различие между параллельным и параллельным может показаться довольно техническим, и некоторые практические примеры были бы полезны. –

+0

@PeterLawrey Я обновил ответ, чтобы содержать ссылки в качестве ссылок. – Scorpion

+1

BTW: Что Скорпион цитирует с веб-сайта jsr166, также является частью официальной документации JDK 7, поэтому мне представляется более подходящим обратиться к людям по адресу http://docs.oracle.com/javase/7/docs/api/. java/util/concurrent/ForkJoinPool.html. –

2

AFAIK, ForkJoinPool работает лучше всего, если вы работаете с большим куском и хотите, чтобы он автоматически разбился. ThreadPoolExecutor - лучший выбор, если вы знаете, как вы хотите разбить работу. По этой причине я склонен использовать последнее, потому что я определил, как я хочу, чтобы работа была разрушена. Как таковой не для каждого.

Его ценность ничего не стоит, когда дело доходит до относительно случайных фрагментов бизнес-логики, ThreadPoolExecutor сделает все, что вам нужно, поэтому зачем делать это сложнее, чем вам нужно.

+1

Позвольте мне (надеюсь) немного уточнить ваше утверждение: ForkJoinTasks не разбивает вашу работу автоматически, но вы должны запрограммировать это в своем коде задачи. Тем не менее, FJT помогает, когда вам нужно ждать результатов таких подзадач, поскольку FJTask может сделать это, не блокируя поток. В отличие от этого, как вы сказали, ThreadPoolExecutor достаточно, когда ваши задачи независимы («случайные фрагменты»). –

+0

Бизнес-логика имеет тенденцию быть случайными. –

1

Давайте сравним различия в конструкторах:

ThreadPoolExecutor

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

ForkJoinPool

ForkJoinPool(int parallelism, 
      ForkJoinPool.ForkJoinWorkerThreadFactory factory, 
      Thread.UncaughtExceptionHandler handler, 
      boolean asyncMode) 

Единственное преимущество, которое я видел в работе ForkJoinPool: механизм кражи работы на холостых потоках.

Java 8 представила еще один API в Executors - newWorkStealingPool, чтобы создать пул кражи работы. Вам не нужно создавать RecursiveTask и RecursiveAction, но все же можете использовать ForkJoinPool.

public static ExecutorService newWorkStealingPool() 

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

Преимущества ThreadPoolExecutor над ForkJoinPool:

  1. Вы можете контролировать размер очереди задач в ThreadPoolExecutor в отличие от ForkJoinPool.
  2. Вы можете применять политики отклоняющих, когда вы запускали из вашей способности в отличие от ForkJoinPool

Мне нравится эти две функции в ThreadPoolExecutor, который сохраняет здоровье системы в хорошем состоянии.

EDIT:

Посмотрите на эту article для случаев использования различных видов услуг Палач бассейнов и оценки ForkJoin Pool параметров резьбы.

 Смежные вопросы

  • Нет связанных вопросов^_^