IllegalMonitorStateException on wait() call

Używam wielowątkowości w Javie dla mojego programu. Uruchomiłem wątek pomyślnie, ale gdy używam Thread.wait(), to rzuca java.lang.IllegalMonitorStateException. Jak sprawić, by wątek poczekał, aż zostanie powiadomiony?

Author: Joachim Sauer, 2009-10-08

10 answers

Musisz być w bloku synchronized, Aby Object.wait() zadziałało.

Zalecam również przeglądanie pakietów współbieżnych zamiast pakietów Old school threading. Są bezpieczniejsze i łatwiejsze do pracy .

Szczęśliwego kodowania.

EDIT

Założyłem, że miałeś na myśli Object.wait() ponieważ Twoim wyjątkiem jest to, co dzieje się, gdy próbujesz uzyskać dostęp bez trzymania blokady obiektów.

 146
Author: reccles,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-22 11:34:44

wait jest zdefiniowana w Object, a nie w Thread. Monitor na Thread jest trochę nieprzewidywalny.

Chociaż wszystkie obiekty Javy mają monitory, generalnie lepiej jest mieć dedykowaną blokadę:

private final Object lock = new Object();
W przeciwieństwie do innych metod diagnostycznych, diagnostyka jest bardzo prosta w obsłudze.]}
private static final class Lock { }
private final Object lock = new Lock();

W celu wait lub notify/notifyAll obiekt, musisz trzymać blokadę za pomocą synchronized. Ponadto, będziesz potrzebować while loop, aby sprawdzić stan przebudzenia (znajdź dobry tekst na wątku, aby wyjaśnić dlaczego).

synchronized (lock) {
    while (!isWakeupNeeded()) {
        lock.wait();
    }
}

Aby powiadomić:

synchronized (lock) {
    makeWakeupNeeded();
    lock.notifyAll();
}

Warto zrozumieć zarówno język Java, jak i java.util.concurrent.locks blokady (i java.util.concurrent.atomic) podczas pracy z wielowątkowością. Ale używaj java.util.concurrent struktur danych, kiedy tylko możesz.

 45
Author: Tom Hawtin - tackline,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-19 15:01:26

Wiem, że ten wątek ma prawie 2 lata, ale nadal muszę go zamknąć, ponieważ również przyszedłem na tę sesję Q/A z tym samym problemem...

Proszę przeczytać tę definicję illegalMonitorException raz po raz...

IllegalMonitorException jest rzucany, aby wskazać, że wątek próbował poczekać na monitor obiektu lub powiadomić inne wątki oczekujące na monitor obiektu bez posiadania określonego monitora.

Ten wiersz raz po raz mówi, IllegalMonitorException pojawia się, gdy występuje jedna z 2 sytuacji....

1> czekać na monitorze obiektu bez posiadania określonego monitora.

2> powiadom inne wątki oczekujące na monitor obiektu bez posiadania określonego monitora.

Niektórzy mogą mieć swoje odpowiedzi... kto nie, to proszę sprawdzić 2 wypowiedzi....

Synchronized (object)

Obiekt.czekaj.()

Jeśli oba obiekty są takie same... więc nie illegalMonitorException może przyjść.

Teraz ponownie przeczytaj definicję IllegalMonitorException i nie zapomnisz jej ponownie...

 21
Author: Mina,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-29 11:35:01

Na podstawie Twoich komentarzy brzmi jakbyś robił coś takiego:

Thread thread = new Thread(new Runnable(){
    public void run() { // do stuff }});

thread.start();
...
thread.wait();

Są dwa problemy. Po pierwsze, jak mówili inni, obj.wait() może być wywołane tylko wtedy, gdy bieżący wątek zawiera prymitywny mutex dla obj. Jeśli bieżący wątek nie zawiera mutex, otrzymasz widoczny wyjątek.

Drugim (ważniejszym) problemem jest to, że thread.wait() nie robi tego, czego się spodziewasz. W szczególności, thread.wait() nie powoduje / align = "left" / Powoduje to raczej, że bieżący wątek będzie czekał, aż jakiś inny wątek wywoła thread.notify() lub thread.notifyAll().

W rzeczywistości nie ma bezpiecznego sposobu, aby zmusić instancję wątku do wstrzymania, jeśli nie chce. (Najbliższa Java jest przestarzała metoda Thread.suspend(), ale ta metoda jest z natury niebezpieczna, jak wyjaśniono w Javadoc.)

Jeśli chcesz, aby nowo rozpoczęty wątek wstrzymał się, najlepszym sposobem na to jest utworzenie instancji CountdownLatch i niech wywołanie wątku await() na zatrzasku zatrzyma się. Główny wątek wywoła countDown() na zatrzasku, aby umożliwić kontynuowanie wstrzymanego wątku.

 3
Author: Stephen C,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-08 15:27:43

Ponieważ nie napisałeś kodu, pracujemy w ciemności. Jakie są szczegóły wyjątku?

dzwonisz do Thread.wait() z wewnątrz wątku, Czy poza nim?

Pytam, ponieważ według javadoc dla IllegalMonitorStateException, jest to:

Rzucony, aby wskazać, że wątek próbował czekać na monitorze obiektu lub powiadomić inne wątki oczekujące na monitorze obiektu bez posiadania określonego monitora.

Aby wyjaśnić tę odpowiedź, to wywołanie oczekiwania na wątku również rzuca IllegalMonitorStateException, mimo że jest wywoływane z zsynchronizowanego bloku:


     private static final class Lock { }
     private final Object lock = new Lock();

    @Test
    public void testRun() {
        ThreadWorker worker = new ThreadWorker();
        System.out.println ("Starting worker");
        worker.start();
        System.out.println ("Worker started - telling it to wait");
        try {
            synchronized (lock) {
                worker.wait();
            }
        } catch (InterruptedException e1) {
            String msg = "InterruptedException: [" + e1.getLocalizedMessage() + "]";
            System.out.println (msg);
            e1.printStackTrace();
            System.out.flush();
        }
        System.out.println ("Worker done waiting, we're now waiting for it by joining");
        try {
            worker.join();
        } catch (InterruptedException ex) { }

    }
 1
Author: CPerkins,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-08 13:33:01

Wątek.wywołanie wait () ma sens wewnątrz kodu synchronizującego się w wątku.obiekt klasy. Chyba nie o to ci chodziło.
Pytasz

Jak sprawić, by wątek poczekał, aż zostanie powiadomiony?

Możesz sprawić, że tylko bieżący wątek będzie czekał. Każdy inny wątek może być tylko delikatnie poproszony, aby poczekać, jeśli się zgodzi.
Jeśli chcesz poczekać na jakiś warunek, potrzebujesz obiektu lock-Thread.class object to bardzo zły wybór - jest to singleton AFAIK więc synchronizacja na to (z wyjątkiem metod statycznych wątku) jest niebezpieczne.
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, na którym nie jesteś zsynchronizowany - jest to nielegalne.

 0
Author: Tadeusz Kopec,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-08 14:12:07

Nie wiem, czy to pomoże komuś innemu, czy nie, ale to była kluczowa część, aby rozwiązać mój problem w odpowiedzi użytkownika "Tom Hawtin - tacklin"powyżej:

synchronized (lock) {
    makeWakeupNeeded();
    lock.notifyAll();
}

Tylko fakt, że "lock" jest przekazywany jako argument w synchronized() i jest również używany w "lock".notifyAll ();

Raz zrobiłem to w tych 2 miejscach i got it working

 0
Author: jp093121,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-10 04:25:54

Otrzymałem IllegalMonitorStateException podczas próby wybudzenia wątku w / z innego class / wątku. W java 8 możesz użyć lock Funkcje nowego interfejsu API współbieżności zamiast z synchronized funkcji.

Przechowywałem już obiekty dla asynchronous transakcji websocket w WeakHashMap. Rozwiązaniem w moim przypadku było również przechowywanie lock obiektu w ConcurrentHashMap dla synchronous odpowiedzi. Uwaga condition.await (Nie .wait).

Do obsługi wielowątkowości użyłem Executors.newCachedThreadPool() aby utworzyć pulę wątków .

 0
Author: Stuart Cardall,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-19 10:29:01

Ci, którzy używają Javy w wersji 7.0 lub niższej, mogą odnieść się do kodu, którego użyłem tutaj i działa.

public class WaitTest {

    private final Lock lock = new ReentrantLock();
    private final Condition condition = lock.newCondition();

    public void waitHere(long waitTime) {
        System.out.println("wait started...");
        lock.lock();
        try {
            condition.await(waitTime, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        lock.unlock();
        System.out.println("wait ends here...");
    }

    public static void main(String[] args) {
        //Your Code
        new WaitTest().waitHere(10);
        //Your Code
    }

}
 0
Author: mannedear,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-20 11:23:27

Aby poradzić sobie z nielegalnym odstępem, musisz sprawdzić, czy wszystkie wywołania metod wait, notify i notifyAll mają miejsce tylko wtedy, gdy wątek wywołujący posiada odpowiedni monitor. Najprostszym rozwiązaniem jest zamknięcie tych wywołań wewnątrz zsynchronizowanych bloków. Obiekt synchronizacji, który zostanie wywołany w instrukcji synchronized, to ten, którego monitor musi zostać przejęty.

Oto prosty przykład na zrozumienie pojęcia of monitor

public class SimpleMonitorState {

    public static void main(String args[]) throws InterruptedException {

        SimpleMonitorState t = new SimpleMonitorState();
        SimpleRunnable m = new SimpleRunnable(t);
        Thread t1 = new Thread(m);
        t1.start();
        t.call();

    }

    public void call() throws InterruptedException {
        synchronized (this) {
            wait();
            System.out.println("Single by Threads ");
        }
    }

}

class SimpleRunnable implements Runnable {

    SimpleMonitorState t;

    SimpleRunnable(SimpleMonitorState t) {
        this.t = t;
    }

    @Override
    public void run() {

        try {
            // Sleep
            Thread.sleep(10000);
            synchronized (this.t) {
                this.t.notify();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
 0
Author: Rakesh Chaudhari,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-10-06 10:35:50