Мне нужно выполнить некоторое количество задач 4 за один раз, что-то вроде этого:
ExecutorService taskExecutor = Executors.newFixedThreadPool(4);
while(...) {
taskExecutor.execute(new MyTask());
}
//...wait for completion somehow
Как я могу получить уведомление, когда все они будут завершены? Пока я не могу думать о чем-то лучше, чем установить какой-либо глобальный счетчик задач и уменьшить его в конце каждой задачи, а затем отслеживать в бесконечном цикле этот счетчик, чтобы он стал 0; или получить список фьючерсов и в бесконечном цикле монитора isDone для всех из них. Каковы лучшие решения без бесконечных циклов?
Спасибо.
Long.MAX_VALUE, TimeUnit.NANOSECONDS
эквивалентна отсутствию тайм-аута.java.util.concurrent
пакету в разделе: Чтобы ждать «навсегда», вы можете использовать значениеTiming
Long.MAX_VALUE
Используйте CountDownLatch :
и в рамках вашей задачи (приложите в try / finally)
источник
ExecutorService.invokeAll()
делает это для вас.источник
futures
они возвращаются, задачи не были выполнены. Они могут завершиться в будущем, и у вас будет ссылка на результат. Вот почему это называетсяFuture
. У вас есть метод Future.get () , который будет ожидать завершения задачи, чтобы получить результат.Вы также можете использовать списки фьючерсов:
затем, когда вы хотите присоединиться ко всем из них, это, по сути, эквивалентно объединению каждого из них (с дополнительным преимуществом в том, что оно вновь вызывает исключения из дочерних потоков в основной):
По сути, уловка заключается в том, чтобы вызывать .get () для каждого Future по одному, вместо бесконечного зацикливания, вызывая isDone () on (все или каждый). Таким образом, вы гарантированно «продвинетесь» через и через этот блок, как только закончится последний поток. Предостережение заключается в том, что, так как вызов .get () повторно вызывает исключения, если один из потоков умирает, вы могли бы подняться из этого, возможно, до того, как другие потоки закончат работу до завершения [чтобы избежать этого, вы могли бы добавить
catch ExecutionException
вызов get ]. Другое предостережение заключается в том, что он сохраняет ссылку на все потоки, поэтому, если у них есть локальные переменные потока, они не будут собираться до тех пор, пока вы не пройдете этот блок (хотя, возможно, вы сможете обойти это, если это станет проблемой, удалив Будущее вне ArrayList). Если вы хотите знать, какое будущее "заканчивается первым"https://stackoverflow.com/a/31885029/32453источник
ExecutorCompletionService.take
: stackoverflow.com/a/11872604/199364В Java8 вы можете сделать это с CompletableFuture :
источник
ExecutorService es = Executors.newFixedThreadPool(4); List< Future<?>> futures = new ArrayList<>(); for(Runnable task : taskList) { futures.add(es.submit(task)); } for(Future<?> future : futures) { try { future.get(); }catch(Exception e){ // do logging and nothing else } }
Просто мои два цента. Чтобы преодолеть требование
CountDownLatch
заранее знать количество задач, вы можете сделать это по старинке, используя простуюSemaphore
.В вашей задаче просто позвоните,
s.release()
как вы быlatch.countDown();
источник
release
вызовы произойдут доacquire
вызова, но после прочтения документации Семафора я вижу, что все в порядке.Немного опоздал к игре, но ради завершения ...
Вместо того, чтобы «ждать» выполнения всех заданий, вы можете думать по принципу Голливуда «не звони мне, я позвоню тебе» - когда я закончу. Я думаю, что полученный код более элегантный ...
Гуава предлагает несколько интересных инструментов для достижения этой цели.
Пример ::
Обернуть ExecutorService в ListeningExecutorService ::
Отправить коллекцию вызовов для исполнения ::
Теперь основная часть:
Прикрепите обратный вызов к ListenableFuture, который вы можете использовать, чтобы получать уведомления, когда все фьючерсы завершены:
Это также дает то преимущество, что вы можете собрать все результаты в одном месте после завершения обработки ...
Больше информации здесь
источник
runOnUiThread()
вonSuccess()
.Класс CyclicBarrier в Java 5 и более поздних версиях предназначен для такого рода вещей.
источник
Следуйте одному из следующих подходов.
submit
наExecutorService
и проверить статус с блокировкой вызоваget()
наFuture
объекте в соответствии с предложениемKiran
invokeAll()
на ExecutorServiceshutdown, awaitTermination, shutdownNow
API ThreadPoolExecutor в правильной последовательностиСвязанные вопросы SE:
Как CountDownLatch используется в многопоточности Java?
Как правильно отключить Java ExecutorService
источник
Здесь есть два варианта, просто запутайте, какой из них лучше всего выбрать.
Опция 1:
Вариант 2:
Здесь положить future.get (); в попытке поймать это хорошая идея, верно?
источник
Вы можете обернуть ваши задачи в другой runnable, который будет отправлять уведомления:
источник
completed
счетчик. Поэтому после их запуска при каждом уведомлении можно было определить, все ли задачи выполнены. Обратите внимание, что крайне важно использовать егоtry/finally
так, чтобы готовое уведомление (или альтернативное уведомление вcatch
блоке) давалось даже в случае сбоя задачи. Иначе бы ждать вечно.Я только что написал пример программы, которая решает вашу проблему. Краткой реализации не дано, поэтому я добавлю ее. Хотя вы можете использовать
executor.shutdown()
иexecutor.awaitTermination()
, это не лучшая практика, поскольку время, затрачиваемое разными потоками, было бы непредсказуемым.источник
Просто, чтобы предоставить больше альтернатив здесь, чтобы использовать защелки / барьеры. Вы также можете получить частичные результаты, пока все они не закончат использование CompletionService .
Из Java Concurrency на практике: «Если у вас есть пакет вычислений для отправки Исполнителю, и вы хотите получать их результаты по мере их появления, вы можете сохранить Future, связанное с каждой задачей, и многократно запрашивать завершение, вызывая get с Тайм-аут нулевой. Это возможно, но утомительно . К счастью, есть лучший способ : услуга завершения. "
Здесь реализация
источник
Это моё решение, основанное на подсказке AdamSkywalker, и оно работает
источник
Вы можете использовать этот код:
источник
Я создал следующий рабочий пример. Идея состоит в том, чтобы иметь способ обработать пул задач (я использую очередь в качестве примера) со многими потоками (определяемыми программно числом numberOfTasks / threshold) и ожидать завершения всех потоков, чтобы продолжить какую-то другую обработку.
Надеюсь, поможет!
источник
Вы можете использовать свой собственный подкласс ExecutorCompletionService для переноса
taskExecutor
и свою собственную реализацию BlockingQueue для получения информации о завершении каждой задачи и выполнения любого обратного вызова или другого действия, которое вы пожелаете, когда количество выполненных задач достигает желаемой цели.источник
Вы должны использовать
executorService.shutdown()
иexecutorService.awaitTermination
метод.Пример следующим образом:
источник
Поэтому я публикую свой ответ по связанному вопросу здесь, если кто-то хочет более простой способ сделать это
источник
Java 8 - Мы можем использовать потоковый API для обработки потока. Пожалуйста, посмотрите фрагмент ниже
источник
Если
doSomething()
бросить некоторые другие исключения,latch.countDown()
кажется, не будет выполняться, так что мне делать?источник
если вы используете несколько потоков ExecutionServices ПОСЛЕДОВАТЕЛЬНО и хотите дождаться завершения КАЖДОГО ИСПОЛНИТЕЛЬНОГО ОБСЛУЖИВАНИЯ. Лучший способ как ниже;
источник
Это может помочь
источник
Вы можете вызвать waitTillDone () в этом классе Runner :
Вы можете повторно использовать этот класс и вызывать waitTillDone () столько раз, сколько хотите, прежде чем вызывать shutdown (), плюс ваш код очень прост . Кроме того, вы не должны знать о количестве задач заранее.
Чтобы использовать его, просто добавьте эту
compile 'com.github.matejtymes:javafixes:1.3.1'
зависимость gradle / maven в ваш проект.Более подробную информацию можно найти здесь:
https://github.com/MatejTymes/JavaFixes
источник
В executor есть метод,
getActiveCount()
который подсчитывает количество активных потоков.После охвата потока мы можем проверить, является ли
activeCount()
значение0
. Если значение равно нулю, это означает, что в данный момент нет активных потоков, что означает, что задача завершена:источник