У меня есть объект с методом StartDownload()
, который запускает три потока.
Как мне получить уведомление, когда каждый поток завершил выполнение?
Есть ли способ узнать, завершен ли один (или весь) поток или все еще выполняется?
java
multithreading
Рикардо Фелгейрас
источник
источник
Ответы:
Есть несколько способов сделать это:
Как реализовать Идею №5? Ну, один из способов - сначала создать интерфейс:
затем создайте следующий класс:
а затем каждый из ваших потоков будет расширяться
NotifyingThread
и вместо реализацииrun()
будет реализованdoRun()
. Таким образом, когда они будут завершены, они автоматически уведомят всех, ожидающих уведомления.Наконец, в вашем основном классе - том, который запускает все потоки (или, по крайней мере, объект, ожидающий уведомления) - измените этот класс
implement ThreadCompleteListener
и сразу после создания каждого потока добавьте себя в список слушателей:затем при выходе из каждого потока ваш
notifyOfThreadComplete
метод будет вызываться с экземпляром потока, который только что завершился (или потерпел крах).Обратите внимание, что лучше было бы
implements Runnable
, чемextends Thread
для,NotifyingThread
поскольку расширение Thread обычно не рекомендуется в новом коде. Но я кодирую ваш вопрос. Если вы изменитеNotifyingThread
класс для реализации,Runnable
вам придется изменить часть кода, который управляет потоками, что довольно просто сделать.источник
notify
метод не внутриrun
метода, а после него.Решение с использованием CyclicBarrier
label0 - создается циклический барьер с количеством сторон, равным количеству выполняемых потоков плюс один для основного потока выполнения (в котором выполняется startDownload ())
метка 1 - n-ый поток загрузки входит в зал ожидания
ярлык 3 - NUMBER_OF_DOWNLOADING_THREADS вошли в комнату ожидания. Основной поток выполнения освобождает их, чтобы они начали выполнять свои задания по загрузке более или менее в одно и то же время.
метка 4 - основной поток выполнения входит в комнату ожидания. Это самая «сложная» часть кода для понимания. Неважно, какой поток во второй раз войдет в комнату ожидания. Важно, чтобы любой поток, входящий в комнату последним, гарантировал, что все другие потоки загрузки завершили свои задания загрузки.
метка 2 - n-й DownloadingThread завершил загрузку и перешел в комнату ожидания. Если это последний, то есть уже NUMBER_OF_DOWNLOADING_THREADS вошли в него, включая основной поток выполнения, основной поток продолжит свое выполнение только после того, как все остальные потоки завершат загрузку.
источник
Вы действительно должны предпочесть решение, которое использует
java.util.concurrent
. Найдите и прочтите по теме Джоша Блоха и / или Брайана Гетца.Если вы не используете потоки
java.util.concurrent.*
и берете на себя ответственность за их использование напрямую, вам, вероятно, следует использовать его,join()
чтобы узнать, когда поток завершен. Вот супер простой механизм обратного вызова. Сначала расширьтеRunnable
интерфейс, чтобы иметь обратный вызов:Затем создайте Executor, который выполнит ваш runnable и перезвонит вам, когда это будет сделано.
Другая очевидная вещь, которую нужно добавить в ваш
CallbackRunnable
интерфейс, - это средство для обработки любых исключений, поэтому, возможно, поместитеpublic void uncaughtException(Throwable e);
строку туда и в свой исполнитель, установите Thread.UncaughtExceptionHandler, чтобы отправить вас к этому методу интерфейса.Но от этого действительно начинает пахнуть
java.util.concurrent.Callable
. Вам действительно стоит взглянуть на использование,java.util.concurrent
если ваш проект это позволяет.источник
runner.join()
а затем с любым кодом, который вы хотите после этого, поскольку вы знаете, что поток завершился. Просто вы можете определить этот код как свойство runnable, чтобы у вас были разные вещи для разных runnables?runner.join()
это самый простой способ подождать. Я предполагал, что OP не хочет блокировать свой основной вызывающий поток, так как они просят «уведомлять» о каждой загрузке, которая может завершаться в любом порядке. Это предлагало один способ получать уведомления асинхронно.Вы хотите дождаться их завершения? Если да, используйте метод Join.
Также существует свойство isAlive, если вы просто хотите его проверить.
источник
Thread
чтобыstart
, что нить делает, но вызов возвращается немедленно.isAlive
должен быть простой тест флага, но когда я погуглил, метод былnative
.Вы можете опросить экземпляр потока с помощью getState (), который возвращает экземпляр перечисления Thread.State с одним из следующих значений:
Однако я думаю, что было бы лучше иметь главный поток, который ожидает завершения трех дочерних элементов, а затем мастер продолжит выполнение, когда остальные 3 закончатся.
источник
Вы также можете использовать
Executors
объект для создания пула потоков ExecutorService . Затем используйте этотinvokeAll
метод для запуска каждого из ваших потоков и получения Futures. Это будет заблокировано, пока все не закончат выполнение. Другой вариант - выполнить каждый из них, используя пул, а затем вызватьawaitTermination
блокировку, пока пул не завершит выполнение. Просто не забудьте вызватьshutdown
(), когда закончите добавлять задачи.источник
Многое изменилось за последние 6 лет в области многопоточности.
Вместо использования
join()
и блокировки API вы можете использовать1. ExecutorService
invokeAll()
API2. CountDownLatch
3. ForkJoinPool или
newWorkStealingPool()
в Executors - другой способ4.Iterate через все
Future
задачи из Подайте наExecutorService
и проверить состояние с блокировкой вызоваget()
наFuture
объектВзгляните на связанные вопросы SE:
Как дождаться потока, который порождает свой собственный поток?
Исполнители: Как синхронно дождаться завершения всех задач, если задачи создаются рекурсивно?
источник
Я бы посоветовал взглянуть на javadoc для класса Thread .
У вас есть несколько механизмов для управления потоками.
Ваш основной поток может
join()
последовательно выполнять три потока и не будет продолжать работу, пока не будут выполнены все три.Периодически опрашивайте состояние порожденных потоков.
Поместите все порождены потоков в отдельный
ThreadGroup
и опрашиватьactiveCount()
наThreadGroup
и ждать его , чтобы добраться до 0.Настройте пользовательский интерфейс обратного вызова или прослушивателя для межпотокового взаимодействия.
Я уверен, что я все еще скучаю по множеству других способов.
источник
Вот решение, которое простое, короткое, легкое для понимания и идеально подходит для меня. Мне нужно было рисовать на экране, когда заканчивается другой поток; но не мог, потому что главный поток контролирует экран. Так:
(1) Я создал глобальную переменную:
boolean end1 = false;
поток устанавливает для нее значение true при завершении. Это подхватывается в основном потоке циклом postDelayed, где на него и реагируют.(2) Моя ветка содержит:
(3) К счастью, postDelayed выполняется в основном потоке, так что именно здесь проверяется другой поток раз в секунду. Когда другой поток заканчивается, он может начать все, что мы захотим делать дальше.
(4) Наконец, запустите все это где-нибудь в вашем коде, вызвав:
источник
Думаю, самый простой способ - использовать
ThreadPoolExecutor
класс.что именно то, что нам нужно. Мы переопределим
afterExecute()
получение обратных вызовов после завершения каждого потока и переопределим,terminated()
чтобы знать, когда все потоки завершены.Итак, вот что вам следует делать
Создайте исполнителя:
И начните свои темы:
Внутренний метод
informUiThatWeAreDone();
делает все, что вам нужно, когда все потоки завершены, например, обновляет пользовательский интерфейс.ПРИМЕЧАНИЕ. Не забывайте об использовании
synchronized
методов, поскольку вы выполняете свою работу параллельно, и БУДЬТЕ ОСТОРОЖНЫ, если решите вызватьsynchronized
метод из другогоsynchronized
метода! Это часто приводит к тупикамНадеюсь это поможет!
источник
Вы также можете использовать SwingWorker, который имеет встроенную поддержку изменения свойств. См. Метод addPropertyChangeListener () или get () для примера прослушивателя изменения состояния.
источник
Посмотрите документацию Java для класса Thread. Вы можете проверить состояние потока. Если вы поместите три потока в переменные-члены, тогда все три потока смогут читать состояния друг друга.
Однако вы должны быть немного осторожны, потому что вы можете вызвать состояние гонки между потоками. Просто постарайтесь избежать сложной логики, основанной на состоянии других потоков. Определенно избегайте записи нескольких потоков в одни и те же переменные.
источник