Mam obiekt z metodą o nazwie StartDownload()
, która uruchamia trzy wątki.
Jak mogę otrzymać powiadomienie o zakończeniu wykonywania każdego wątku?
Czy istnieje sposób, aby dowiedzieć się, czy jeden (lub cały) wątek jest zakończony lub nadal jest wykonywany?
java
multithreading
Ricardo Felgueiras
źródło
źródło
Odpowiedzi:
Można to zrobić na kilka sposobów:
Jak wdrożyć Pomysł nr 5? Cóż, jednym ze sposobów jest najpierw utworzenie interfejsu:
następnie utwórz następującą klasę:
a wtedy każdy z twoich wątków rozszerzy się
NotifyingThread
i zamiast implementowaćrun()
, zaimplementujedoRun()
. Dlatego po zakończeniu automatycznie powiadomią każdego, kto czeka na powiadomienie.Na koniec w swojej głównej klasie - tej, która uruchamia wszystkie wątki (lub przynajmniej obiekt oczekujący na powiadomienie) - zmodyfikuj tę klasę do
implement ThreadCompleteListener
i natychmiast po utworzeniu każdego wątku dodaj się do listy słuchaczy:następnie, gdy każdy wątek zostanie zamknięty, Twoja
notifyOfThreadComplete
metoda zostanie wywołana z instancją Thread, która właśnie się zakończyła (lub uległa awarii).Należy pamiętać, że lepiej byłoby
implements Runnable
, zamiastextends Thread
naNotifyingThread
miarę rozciągania wątek jest zwykle zniechęca w nowym kodem. Ale koduję na twoje pytanie. Jeśli zmieniszNotifyingThread
klasę do zaimplementowaniaRunnable
, musisz zmienić część kodu, który zarządza wątkami, co jest dość proste.źródło
notify
metodę nie w jej wnętrzurun
, ale po niej.Rozwiązanie wykorzystujące CyclicBarrier
label0 - tworzona jest cykliczna bariera z liczbą stron równą liczbie wykonujących się wątków plus jeden dla głównego wątku wykonania (w którym wykonywany jest startDownload ())
etykieta 1 - n-ty DownloadingThread wchodzi do poczekalni
etykieta 3 - NUMBER_OF_DOWNLOADING_THREADS weszło do poczekalni. Główny wątek wykonania zwalnia je, aby rozpocząć wykonywanie zadań pobierania mniej więcej w tym samym czasie
etykieta 4 - do poczekalni wchodzi główny wątek wykonania. To jest najtrudniejsza do zrozumienia część kodu. Nie ma znaczenia, który wątek wejdzie do poczekalni po raz drugi. Ważne jest, aby każdy wątek wchodzący do pokoju jako ostatni zapewniał, że wszystkie inne wątki pobierania zakończyły swoje zadania pobierania.
etykieta 2 - n-ty DownloadingThread zakończył zadanie pobierania i wchodzi do poczekalni. Jeśli jest to ostatni, tj. Już NUMBER_OF_DOWNLOADING_THREADS weszło do niego, łącznie z głównym wątkiem wykonania, główny wątek będzie kontynuował wykonywanie dopiero po zakończeniu pobierania wszystkich pozostałych wątków.
źródło
Naprawdę powinieneś preferować rozwiązanie, które wykorzystuje
java.util.concurrent
. Znajdź i przeczytaj Josha Blocha i / lub Briana Goetza na ten temat.Jeśli nie używasz
java.util.concurrent.*
bezpośrednio wątków i bierzesz za nie odpowiedzialność, prawdopodobnie powinieneś użyć funkcji,join()
aby wiedzieć, kiedy wątek jest gotowy. Oto super prosty mechanizm wywołania zwrotnego. Najpierw rozszerzRunnable
interfejs, aby mieć wywołanie zwrotne:Następnie stwórz Executor, który wykona twój runnable i oddzwoni, kiedy to się skończy.
Inną oczywistą rzeczą, którą można dodać do
CallbackRunnable
interfejsu, jest sposób obsługi wszelkich wyjątków, więc może umieść tampublic void uncaughtException(Throwable e);
linię, a w module wykonawczym zainstaluj Thread.UncaughtExceptionHandler, aby wysłać cię do tej metody interfejsu.Ale robienie tego wszystkiego naprawdę zaczyna pachnieć
java.util.concurrent.Callable
. Powinieneś naprawdę spojrzeć na użycie,java.util.concurrent
jeśli twój projekt na to pozwala.źródło
runner.join()
a potem dowolny kod, który chcesz po tym, ponieważ wiesz, że wątek się skończył. Czy po prostu możesz zdefiniować ten kod jako właściwość elementu wykonawczego, więc możesz mieć różne rzeczy dla różnych elementów wykonawczych?runner.join()
to najbardziej bezpośredni sposób oczekiwania. Zakładałem, że OP nie chciał blokować swojego głównego wątku wywołującego, ponieważ prosił o „powiadamianie” o każdym pobieraniu, które mogło zakończyć się w dowolnej kolejności. To oferowało jeden ze sposobów asynchronicznego otrzymywania powiadomień.Czy chcesz poczekać, aż skończą? Jeśli tak, użyj metody Join.
Istnieje również właściwość isAlive, jeśli chcesz ją tylko sprawdzić.
źródło
Thread
dostart
, co robi wątek, ale wywołanie natychmiast wraca.isAlive
powinien być prostym testem flagowym, ale kiedy googlowałem, metoda byłanative
.Możesz przesłuchać wystąpienie wątku za pomocą metody getState (), która zwraca wystąpienie wyliczenia Thread.State z jedną z następujących wartości:
Jednak myślę, że lepszym rozwiązaniem byłoby posiadanie głównego wątku, który czeka na zakończenie trojga dzieci, a następnie master kontynuowałby wykonywanie, gdy pozostałe 3 skończą.
źródło
Możesz również użyć
Executors
obiektu do utworzenia puli wątków ExecutorService . Następnie użyj tejinvokeAll
metody, aby uruchomić każdy z wątków i pobrać Futures. Spowoduje to zablokowanie, dopóki wszyscy nie zakończą wykonywania. Inną opcją byłoby wykonanie każdego z nich przy użyciu puli, a następnie wywołanieawaitTermination
bloku do momentu zakończenia wykonywania puli. Po prostu nie zapomnij wywołaćshutdown
() po zakończeniu dodawania zadań.źródło
Wiele rzeczy zmieniło się w ciągu ostatnich 6 lat na froncie wielowątkowym.
Zamiast używać
join()
i blokować API, możesz użyć1. ExecutorService
invokeAll()
API2. CountDownLatch
3. ForkJoinPool lub
newWorkStealingPool()
w Executorach jest w inny sposób4.Powtarzaj wszystkie
Future
zadania od momentu przesłaniaExecutorService
i sprawdź status zget()
włączonym blokowaniem połączeniaFuture
obiekcieSpójrz na powiązane pytania dotyczące SE:
Jak czekać na wątek, który odrodzi swój własny wątek?
Wykonawcy: jak synchronicznie czekać, aż wszystkie zadania zostaną zakończone, jeśli zadania są tworzone rekurencyjnie?
źródło
Proponuję zajrzeć do javadoc dla klasy Thread .
Masz wiele mechanizmów manipulacji wątkami.
Twój główny wątek może
join()
wykonywać trzy wątki szeregowo i nie będzie kontynuowany, dopóki wszystkie trzy nie zostaną zakończone.Sonduj stan wątków utworzonych wątków w odstępach czasu.
Umieść wszystkie utworzone wątki w osobnym
ThreadGroup
i odpytajactiveCount()
naThreadGroup
i poczekaj, aż osiągnie 0.Skonfiguruj niestandardowy interfejs wywołania zwrotnego lub nasłuchiwania do komunikacji między wątkami.
Jestem pewien, że wciąż brakuje mi wielu innych sposobów.
źródło
Oto rozwiązanie, które jest proste, krótkie, łatwe do zrozumienia i doskonale dla mnie działa. Musiałem rysować na ekranie, gdy kończy się kolejny wątek; ale nie mógł, ponieważ główny wątek ma kontrolę nad ekranem. Więc:
(1) Utworzyłem zmienną globalną:
boolean end1 = false;
wątek ustawia ją na true po zakończeniu. Jest to odbierane w głównym wątku przez pętlę „postDelayed”, na której jest udzielana odpowiedź.(2) Mój wątek zawiera:
(3) Na szczęście „postDelayed” jest uruchamiany w głównym wątku, więc to jest miejsce, w którym co sekundę sprawdza inny wątek. Kiedy kończy się drugi wątek, może to rozpocząć się od tego, co chcemy robić dalej.
(4) Na koniec zacznij całą operację gdzieś w kodzie, wywołując:
źródło
Myślę, że najłatwiej jest użyć
ThreadPoolExecutor
klasy.czyli dokładnie to, czego potrzebujemy. Nadpisujemy,
afterExecute()
aby uzyskać wywołania zwrotne po zakończeniu każdego wątku i nadpisujemyterminated()
aby wiedzieć, kiedy wszystkie wątki są zakończone.Oto, co powinieneś zrobić
Utwórz executor:
I rozpocznij swoje wątki:
Metoda wewnętrzna
informUiThatWeAreDone();
zrób wszystko, co musisz zrobić, gdy wszystkie wątki zostaną ukończone, na przykład zaktualizuj interfejs użytkownika.UWAGA: Nie zapomnij o używaniu
synchronized
metod, ponieważ wykonujesz swoją pracę równolegle i BĄDŹ BARDZO OSTROŻNY, jeśli zdecydujesz się wywołaćsynchronized
metodę z innegosynchronized
metody! To często prowadzi do impasuMam nadzieję że to pomoże!
źródło
Możesz także użyć SwingWorker, który ma wbudowaną obsługę zmiany właściwości. Zobacz addPropertyChangeListener () lub metodę get () , aby zapoznać się z przykładem detektora zmiany stanu.
źródło
Zapoznaj się z dokumentacją Java dotyczącą klasy Thread. Możesz sprawdzić stan wątku. Jeśli umieścisz trzy wątki w zmiennych składowych, wszystkie trzy wątki będą mogły czytać swoje stany.
Musisz jednak być trochę ostrożny, ponieważ możesz spowodować wyścigi między wątkami. Po prostu staraj się unikać skomplikowanej logiki opartej na stanie innych wątków. Zdecydowanie unikaj zapisywania wielu wątków do tych samych zmiennych.
źródło