W moim programie używam wielowątkowości w Javie. Uruchomiłem wątek pomyślnie, ale kiedy używam Thread.wait()
, rzuca java.lang.IllegalMonitorStateException
. Jak mogę sprawić, by wątek czekał, aż zostanie powiadomiony?
java
multithreading
wait
prakash.panjwani
źródło
źródło
Odpowiedzi:
Aby pracować, musisz być w
synchronized
blokuObject.wait()
.Polecam również przyjrzenie się pakietom współbieżności zamiast pakietów wątków starej szkoły. Są bezpieczniejsze i łatwiejsze w obsłudze .
Miłego kodowania.
EDYTOWAĆ
Założyłem, że
Object.wait()
jako wyjątek miałeś na myśli to, co dzieje się, gdy próbujesz uzyskać dostęp bez blokowania obiektów.źródło
wait
jest zdefiniowany w programieObject
, a nie w nimThread
. Monitor włączonyThread
jest trochę nieprzewidywalny.Chociaż wszystkie obiekty Java mają monitory, generalnie lepiej jest mieć dedykowaną blokadę:
Możesz uzyskać nieco łatwiejszą do odczytania diagnostykę przy niewielkim koszcie pamięci (około 2 KB na proces), używając nazwanej klasy:
Aby obiekt
wait
lubnotify
/notifyAll
obiekt, musisz trzymać blokadę zsynchronized
instrukcją. Będziesz także potrzebowałwhile
pętli, aby sprawdzić stan wybudzania (znajdź dobry tekst na temat wątków, aby wyjaśnić, dlaczego).Powiadamiać:
Podczas wchodzenia w wielowątkowość warto poznać zarówno język Java, jak i
java.util.concurrent.locks
blokady (ijava.util.concurrent.atomic
). Ale używajjava.util.concurrent
struktur danych, kiedy tylko możesz.źródło
wait
, tak, nigdy byś tego nie zrobiłnotify
. Jednak w dokumentacji API dlaObject.wait
„Wątek zwalnia własność tego monitora”. Więc gdy jest w środkuwait
, jest tak, jakby był poza otaczającymisynchronized
blokami (dla tego samego obiektu może być wielesynchronized
bloków na tym samym obiekcie).Wiem, że ten wątek ma prawie 2 lata, ale nadal muszę go zamknąć, ponieważ przyszedłem również do tej sesji Q / A z tym samym problemem ...
Przeczytaj tę definicję nielegalnego wyjątku MonitorException raz po raz ...
IllegalMonitorException jest generowany w celu wskazania, że wątek próbował czekać na monitorze obiektu lub aby powiadomić inne wątki oczekujące na monitorze obiektu bez posiadania określonego monitora.
Ta linia wielokrotnie mówi, że IllegalMonitorException pojawia się, gdy wystąpi jedna z 2 sytuacji ...
1> czekaj na monitorze obiektu bez posiadania określonego monitora.
2> powiadomić inne wątki oczekujące na monitorze obiektu bez posiadania określonego monitora.
Niektórzy mogliby mieć odpowiedzi ... a kto nie, sprawdź 2 stwierdzenia ...
zsynchronizowany (obiekt)
object.wait ()
Jeśli oba obiekty są takie same ... wtedy nie może nadejść żaden nielegalny wyjątek MonitorException.
Teraz ponownie przeczytaj definicję IllegalMonitorException i nie zapomnisz o tym ponownie ...
źródło
Na podstawie twoich komentarzy wygląda na to, że robisz coś takiego:
Są trzy problemy.
Jak powiedzieli inni,
obj.wait()
można go wywołać tylko wtedy, gdy bieżący wątek przechowuje pierwotną blokadę / mutex dlaobj
. Jeśli bieżący wątek nie utrzymuje blokady, pojawi się wyjątek, który widzisz.thread.wait()
Połączenie nie robi tego, co wydaje się być spodziewałem się zrobić. W szczególnościthread.wait()
nie powoduje, że nominowany wątek czeka. Raczej powoduje, że bieżący wątek czeka, aż inne wywołania wątkuthread.notify()
lubthread.notifyAll()
.W rzeczywistości nie ma bezpiecznego sposobu na zmuszenie
Thread
instancji do wstrzymania, jeśli nie chce. (Najbliżej tego, co ma Java, jestThread.suspend()
metoda przestarzała , ale ta metoda jest z natury niebezpieczna, jak wyjaśniono w Javadoc.)Jeśli chcesz, aby nowo rozpoczęty
Thread
pauzował, najlepszym sposobem na to jest utworzenieCountdownLatch
instancji i wywołanie wątkuawait()
na zatrzasku, aby wstrzymało się. Główny wątek wywołałby wówczascountDown()
zatrzask, aby umożliwić kontynuację wstrzymanego wątku.Prostopadłe do poprzednich punktów, użycie
Thread
obiektu jako blokady / muteksu może powodować problemy. Na przykład javadoc dlaThread::join
mówi:źródło
Ponieważ nie opublikowałeś kodu, pracujemy po omacku. Jakie są szczegóły wyjątku?
Czy wywołujesz Thread.wait () z poziomu wątku, czy poza nim?
Pytam o to, ponieważ zgodnie z javadoc dla IllegalMonitorStateException jest to:
Aby wyjaśnić tę odpowiedź, to wywołanie oczekiwania na wątek zgłasza również wyjątek IllegalMonitorStateException, mimo że jest wywoływany z zsynchronizowanego bloku:
źródło
wait()
.worker.wait()
linii? Wtedy powinieneś synchronizować się z pracownikiem, a nie z zamkiem.Aby poradzić sobie z wyjątkiem IllegalMonitorStateException, należy sprawdzić, czy wszystkie wywołania metod wait, notification i notifyAll mają miejsce tylko wtedy, gdy wątek wywołujący jest właścicielem odpowiedniego monitora . Najprostszym rozwiązaniem jest umieszczenie tych wywołań w zsynchronizowanych blokach. Obiekt synchronizacji, który ma zostać wywołany w zsynchronizowanej instrukcji, to ten, którego monitor należy pobrać.
Oto prosty przykład zrozumienia pojęcia monitora
źródło
Wywołanie Thread.wait () ma sens w kodzie, który synchronizuje się z obiektem Thread.class. Nie sądzę, że to miałeś na myśli.
Ty pytasz
Możesz sprawić, by czekał tylko bieżący wątek. Każdy inny wątek może zostać delikatnie poproszony o czekanie, jeśli się zgodzi.
Jeśli chcesz poczekać na jakiś warunek, potrzebujesz obiektu blokującego - obiekt Thread.class to bardzo zły wybór - jest to singleton AFAIK, więc synchronizacja na nim (poza metodami statycznymi Thread) jest niebezpieczna.
Szczegóły dotyczące synchronizacji i oczekiwania zostały już wyjaśnione przez Toma Hawtina.
java.lang.IllegalMonitorStateException
oznacza, że próbujesz czekać na obiekt, z którym nie jesteś zsynchronizowany - jest to nielegalne.źródło
Nie jestem pewien, czy to pomoże komuś innemu, czy nie, ale to była kluczowa część rozwiązania mojego problemu w odpowiedzi użytkownika „Tom Hawtin - tacklin” powyżej:
Po prostu fakt, że "lock" jest przekazywany jako argument w synchronized () i jest również używany w "lock" .notifyAll ();
Kiedy już zrobiłem to w tych 2 miejscach, to działało
źródło
Przez
IllegalMonitorStateException
chwilę próbowałem obudzić wątek w / z innegoclass
/ wątku. Wjava 8
można wykorzystaćlock
możliwości nowego Współbieżnym API zamiast zsynchronized
funkcji.Przechowywałem już obiekty dla
asynchronous
transakcji WebSocket w plikuWeakHashMap
. Rozwiązaniem w moim przypadku było również przechowywanielock
obiektu w aConcurrentHashMap
dlasynchronous
odpowiedzi. Zwróć uwagę nacondition.await
(nie.wait
).Aby obsłużyć wielowątkowość, użyłem a
Executors.newCachedThreadPool()
do utworzenia puli wątków .źródło
Ci, którzy używają Javy 7.0 lub niższej, mogą odwołać się do kodu, którego tutaj użyłem i działa.
źródło