Как проще всего дождаться ExecutorService
завершения всех заданий ? Моя задача в основном вычислительная, поэтому я просто хочу выполнить большое количество заданий - по одному на каждое ядро. Прямо сейчас моя установка выглядит так:
ExecutorService es = Executors.newFixedThreadPool(2);
for (DataTable singleTable : uniquePhrases) {
es.execute(new ComputeDTask(singleTable));
}
try{
es.wait();
}
catch (InterruptedException e){
e.printStackTrace();
}
ComputeDTask
реализует работоспособный. Это кажется для правильного выполнения задач, но код падает wait()
с IllegalMonitorStateException
. Это странно, потому что я поиграл с некоторыми игрушечными примерами, и это сработало.
uniquePhrases
содержит несколько десятков тысяч элементов. Должен ли я использовать другой метод? Я ищу что-то максимально простое
java
multithreading
threadpool
executorservice
джордж смайлик
источник
источник
es
), когда вы хотите его ждать - блокировка будет автоматически снята во время ожиданияExecutors.newFixedThreadPool(System.getRuntime().availableProcessors());
Ответы:
Самый простой подход - это использовать
ExecutorService.invokeAll()
то, что вы хотите в одной строке. На вашем языке вам нужно изменить или перенести,ComputeDTask
чтобы реализоватьCallable<>
, что может дать вам немного больше гибкости. Вероятно, в вашем приложении есть значимая реализацияCallable.call()
, но вот способ обернуть его, если не использоватьExecutors.callable()
.Как уже отмечали другие, вы можете использовать версию тайм-аута,
invokeAll()
если это необходимо. В этом примереanswers
он будет содержать наборFuture
s, которые будут возвращать нули (см. ОпределениеExecutors.callable()
. Вероятно, вы хотите сделать небольшой рефакторинг, чтобы вы могли получить полезный ответ или ссылку на базовый кодComputeDTask
, но я могу не скажи из твоего примера.Если это не ясно, обратите внимание, что
invokeAll()
не вернется, пока все задачи не будут выполнены. (т.е. всеFuture
s в вашейanswers
коллекции сообщат,.isDone()
если их спросят.) Это позволяет избежать ручного выключения, awaitTermination и т. д. и позволяет вам использовать этоExecutorService
аккуратно для нескольких циклов, если это необходимо.Есть несколько связанных вопросов по SO:
Как ждать завершения всех потоков
Возвращаемые значения из потоков Java
invokeAll () не желает принимать коллекцию <Callable <t >>
Нужно ли синхронизировать?
Ни один из них не является строго точным для вашего вопроса, но они дают немного цвета о том, как люди думают
Executor
/ExecutorService
должны быть использованы.источник
Если вы хотите дождаться завершения всех задач, используйте
shutdown
метод вместоwait
. Тогда следуйте за этим сawaitTermination
.Также вы можете использовать
Runtime.availableProcessors
количество аппаратных потоков, чтобы правильно инициализировать пул потоков.источник
awaitTermination
требует времени ожидания в качестве параметра. Хотя можно обеспечить ограниченное время и разместить цикл вокруг него, чтобы дождаться завершения всех потоков, мне было интересно, есть ли более элегантное решение.Если ждет всех задач в
ExecutorService
до конца не точно ваша цель, а ждет , пока конкретная партия задач не завершена, вы можете использоватьCompletionService
- конкретно,ExecutorCompletionService
.Идея состоит в том, чтобы создать
ExecutorCompletionService
упаковкуExecutor
, отправить через нее некоторое известное количество задачCompletionService
, а затем извлечь то же число результатов из очереди завершения, используяtake()
(какие блоки) илиpoll()
(какие нет). Как только вы нарисовали все ожидаемые результаты, соответствующие заданным вами задачам, вы знаете, что все они выполнены.Позвольте мне заявить об этом еще раз, потому что это не очевидно из интерфейса: вы должны знать, сколько вещей вы положили
CompletionService
в, чтобы узнать, сколько вещей нужно попытаться вытянуть. Это особенно важно дляtake()
метода: вызывайте его один раз слишком много, и он будет блокировать ваш вызывающий поток, пока какой-то другой поток не отправит другую работу тому же самомуCompletionService
.Есть несколько примеров, показывающих, как использовать
CompletionService
в книге Java Concurrency in Practice .источник
CompletionService
Если вы хотите подождать, пока служба исполнителя завершит выполнение, вызовите,
shutdown()
а затем awaitTermination (units, unitType) , напримерawaitTermination(1, MINUTE)
. ExecutorService не блокирует на своем собственном мониторе, поэтому вы не можете использоватьwait
и т.д.источник
awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
stackoverflow.com/a/1250655/32453Вы можете подождать, пока работа завершится через определенный интервал:
Или вы могли бы использовать ExecutorService . submit ( Runnable ) и собирать объекты Future, которые он возвращает, и вызывать get () для каждого по очереди, чтобы дождаться их завершения.
InterruptedException чрезвычайно важен для правильной обработки. Это то, что позволяет вам или пользователям вашей библиотеки безопасно завершить долгий процесс.
источник
Просто используйте
В каждой теме
и как барьер
источник
Основная причина для IllegalMonitorStateException :
Из вашего кода вы только что вызвали wait () на ExecutorService без владения блокировкой.
Ниже код исправит
IllegalMonitorStateException
Следуйте одному из следующих подходов, чтобы дождаться завершения всех задач, которые были представлены
ExecutorService
.Перебирайте все
Future
задачи с моментаsubmit
включенияExecutorService
и проверяйте статус с блокировкой вызоваget()
наFuture
объектеИспользование invokeAll на
ExecutorService
Использование CountDownLatch
Используя ForkJoinPool или newWorkStealingPool из
Executors
(начиная с Java 8)Выключите пул, как рекомендовано на странице документации оракула.
Если вы хотите изящно дождаться завершения всех задач, когда вы используете опцию 5 вместо опций с 1 по 4, измените
в
а,
while(condition)
который проверяет каждую 1 минуту.источник
Ты можешь использовать
ExecutorService.invokeAll
метод, он выполнит все задачи и подождет, пока все потоки не завершат свою задачу.Здесь завершено Javadoc
Вы также можете использовать перегруженную версию этого метода, чтобы указать время ожидания.
Вот пример кода с
ExecutorService.invokeAll
источник
У меня также есть ситуация, когда у меня есть набор документов для сканирования. Я начну с исходного «начального» документа, который должен быть обработан, этот документ содержит ссылки на другие документы, которые также должны быть обработаны, и так далее.
В моей основной программе я просто хочу написать что-то вроде следующего, где
Crawler
контролирует кучу потоков.Та же самая ситуация произошла бы, если бы я хотел перемещаться по дереву; я бы вставил в корневой узел, процессор для каждого узла добавлял бы детей в очередь по мере необходимости, и группа потоков обрабатывала бы все узлы в дереве, пока их больше не было.
Я не смог найти ничего в JVM, что мне показалось немного удивительным. Поэтому я написал класс,
ThreadPool
который можно использовать напрямую или подкласс для добавления методов, подходящих для домена, напримерschedule(Document)
. Надеюсь, поможет!ThreadPool Javadoc | специалист
источник
Добавьте все темы в коллекцию и отправьте, используя
invokeAll
. Если вы можете использоватьinvokeAll
методExecutorService
, JVM не перейдет к следующей строке, пока все потоки не будут завершены.Вот хороший пример: invokeAll через ExecutorService
источник
Отправьте свои задачи в Runner, а затем дождитесь вызова метода waitTillDone () следующим образом:
Чтобы использовать его, добавьте эту зависимость gradle / maven:
'com.github.matejtymes:javafixes:1.0'
Для получения более подробной информации смотрите здесь: https://github.com/MatejTymes/JavaFixes или здесь: http://matejtymes.blogspot.com/2016/04/executor-that-notifies-you-when-task.html
источник
Простая альтернатива этому - использовать потоки вместе с join. См .: Присоединение Темы
источник
Я просто подожду, пока исполнитель завершит работу с указанным тайм-аутом, который, по вашему мнению, подходит для выполнения задач.
источник
Похоже, вам нужно
ForkJoinPool
и использовать глобальный пул для выполнения задач.Прелесть в
pool.awaitQuiescence
том, что метод блокирует использование потока вызывающей стороны для выполнения своих задач, а затем возвращает его, когда он действительно пуст.источник