Ответ 1
ForkJoinPool
Исходный код имеет приятный раздел под названием "Обзор реализации", прочитанный для получения окончательной правды. Ниже приводится объяснение для JDK 8u40.
Начиная с первого дня, ForkJoinPool
имел рабочую очередь на рабочий поток (назовите их "рабочие очереди" ). Разбитые задачи вставляются в локальную рабочую очередь, готовые к повторной загрузке рабочего и выполняются - другими словами, это выглядит как стек из перспективы рабочего потока. Когда рабочий истощает свою рабочую очередь, он обходит и пытается украсть задания из других рабочих очередей. Это "кража работы".
Теперь, перед (IIRC) JDK 7u12, ForkJoinPool
была одна глобальная очередь подачи. Когда рабочие потоки исчерпали локальные задачи, а также задачи кражи, они добрались туда и попытались выяснить, доступна ли внешняя работа. В этом дизайне нет преимущества против регулярного, скажем, ThreadPoolExecutor
, поддерживаемого ArrayBlockingQueue
.
После этого он значительно изменился. После того, как эта очередь представления была идентифицирована как серьезное узкое место в производительности, Doug Lea и др. чередуя очереди отправки. Оглядываясь назад, это очевидная идея: вы можете повторно использовать большую часть механики, доступную для рабочих очередей. Вы даже можете свободно распределять эти очереди отправки на рабочие потоки. Теперь внешняя подача переходит в одну из очередей отправки. Затем, работники, которые не имеют работы для того, чтобы намазать, могут сначала просмотреть очередь представления, связанную с конкретным работником, а затем бродить вокруг, глядя в очереди отправки других. Можно также называть это "кражу работы".
Я видел много рабочих нагрузок, пользующихся этим. Это особое преимущество дизайна ForkJoinPool
даже для простых нерекурсивных задач было признано давно. Многие пользователи в concurrency -interest @попросили простого исполняющего роль рабочего исполнителя без всего ForkJoinPool
arcanery. Это одна из причин, почему у нас Executors.newWorkStealingPool()
в JDK 8 onward - в настоящее время делегируется ForkJoinPool
, но открывается для предоставления более простая реализация.