IllegalMonitorStateException при ожидании () вызова

Я использую многопоточность в Java для моей программы. Я успешно запустил поток, но когда я использую Thread.wait()это бросает java.lang.IllegalMonitorStateException, Как я могу заставить поток ждать, пока он не будет уведомлен?

12 ответов

Решение

Вы должны быть в synchronized блок для того, чтобы Object.wait() работать.

Кроме того, я рекомендую смотреть на пакеты параллелизма вместо пакетов старой школы. Они безопаснее и с ними проще работать.

Удачного кодирования.

РЕДАКТИРОВАТЬ

Я предполагал, что ты имел в виду Object.wait() Исключением является то, что происходит, когда вы пытаетесь получить доступ, не удерживая блокировку объектов.

wait определяется в Objectи не это Thread, Монитор на Thread немного непредсказуемо.

Хотя все объекты Java имеют мониторы, обычно лучше иметь выделенную блокировку:

private final Object lock = new Object();

Диагностику можно немного легче прочитать при небольших затратах памяти (около 2 КБ на процесс), используя именованный класс:

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

Чтобы wait или же notify/notifyAll объект, вы должны держать замок с synchronized заявление. Также вам понадобится while цикл, чтобы проверить условие пробуждения (найдите хороший текст о потоке, чтобы объяснить, почему).

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

Уведомить:

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

Стоит понять и язык Java, и java.util.concurrent.locks замки (и java.util.concurrent.atomic) при переходе в многопоточность. Но использовать java.util.concurrent структуры данных, когда вы можете.

Я знаю, что этой ветке уже почти 2 года, но все еще нужно закрыть ее, так как я также пришел на этот сеанс вопросов и ответов с той же проблемой...

Пожалуйста, прочитайте это определение нелегальной MonitorException снова и снова...

IllegalMonitorException генерируется, чтобы указать, что поток попытался ждать на мониторе объекта или уведомить другие потоки, ожидающие на мониторе объекта, не имея указанного монитора.

Эта строка снова и снова говорит, что IllegalMonitorException возникает, когда возникает одна из двух ситуаций....

1> ждать на мониторе объекта, не имея указанного монитора.

2> уведомить другие потоки, ожидающие на мониторе объекта, не имея указанного монитора.

У некоторых, возможно, есть свои ответы... кто все не имеет, тогда, пожалуйста, проверьте 2 утверждения....

синхронизированный (объект)

Object.wait()

Если оба объекта одинаковы..., тогда не может появиться незаконное исключение.

Теперь снова прочитайте определение IllegalMonitorException, и вы не забудете его снова...

На основании ваших комментариев кажется, что вы делаете что-то вроде этого:

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

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

Есть три проблемы.

  1. Как уже говорили другие, obj.wait() может быть вызван только если текущий поток содержит примитив блокировки / мьютекса для obj, Если текущий поток не удерживает блокировку, вы получаете исключение, которое вы видите.

  2. thread.wait() Вызов не делает то, что вы, кажется, ожидаете. В частности, thread.wait() не заставляет назначенный поток ждать. Скорее это заставляет текущий поток ждать, пока некоторые другие вызовы потока thread.notify() или же thread.notifyAll(),

    На самом деле нет безопасного способа заставить Thread экземпляр, чтобы сделать паузу, если он не хочет. (Ближайшее, что Java имеет к этому, является устаревшим Thread.suspend() метод, но этот метод по своей сути небезопасен, как объясняется в Javadoc.)

    Если вы хотите, чтобы недавно началось Thread чтобы сделать паузу, лучший способ сделать это - создать CountdownLatch экземпляр и вызов потока await() на защелку, чтобы сделать паузу сам. Основной поток будет тогда вызывать countDown() на защелке, чтобы продолжить приостановленную нить.

  3. Ортогонально предыдущим точкам, используя Thread Объект как блокировка / мьютекс может вызвать проблемы. Например, Javadoc для Thread::join говорит:

    Эта реализация использует цикл this.wait звонки обусловлены this.isAlive, Как поток завершает this.notifyAll метод вызывается. Рекомендуется, чтобы приложения не использовали wait, notify, или же notifyAll на Thread экземпляров.

Чтобы иметь дело с IllegalMonitorStateException, вы должны убедиться, что все вызовы методов wait, notify и notifyAll происходят только тогда, когда вызывающий поток владеет соответствующим монитором. Самое простое решение - заключить эти вызовы в синхронизированные блоки. Объект синхронизации, который должен вызываться в операторе синхронизации, - это тот, чей монитор должен быть получен.

Вот простой пример для понимания концепции монитора

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();
        }
    }
}

Поскольку вы не разместили код, мы вроде как работаем в темноте. Какие детали исключения?

Вы вызываете Thread.wait() из потока или вне его?

Я спрашиваю об этом, потому что в соответствии с javadoc для IllegalMonitorStateException, это:

Брошенный, чтобы указать, что поток попытался ждать на мониторе объекта или уведомить другие потоки, ожидающие на мониторе объекта, не имея указанного монитора.

Чтобы прояснить этот ответ, этот вызов ожидания в потоке также вызывает исключение IllegalMonitorStateException, несмотря на то, что он вызывается из синхронизированного блока:


     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) { }

    }

Методы wait(), notify() и notifyAll() следует вызывать только в синхронизированных контекстах.

Например, в синхронизированном блоке:

      syncronized (obj) {
        obj.wait();
}

Или, в синхронизированном методе:

      syncronized static void myMethod() {
        wait();
}

Вызов Thread.wait() имеет смысл внутри кода, который синхронизируется с объектом Thread.class. Я не думаю, что это то, что вы имели в виду.
Ты спрашиваешь

Как я могу заставить поток ждать, пока он не будет уведомлен?

Вы можете подождать только свою текущую тему. Любую другую ветку можно только осторожно попросить подождать, если она согласится.
Если вы хотите подождать какое-то условие, вам нужен объект блокировки - объект Thread.class - очень плохой выбор - это одноэлементный AFAIK, поэтому синхронизация на нем (за исключением статических методов Thread) опасна.
Подробности синхронизации и ожидания уже объясняются Томом Хоутином.java.lang.IllegalMonitorStateException означает, что вы пытаетесь дождаться объекта, с которым вы не синхронизированы - это незаконно.

Я получил IllegalMonitorStateException при попытке разбудить нить в / из другого class / нить. В java 8 Вы можете использовать lock функции нового API параллелизма вместо synchronized функции.

Я уже хранил предметы для asynchronous транзакции websocket в WeakHashMap, Решением в моем случае было также хранить lock объект в ConcurrentHashMap за synchronous ответы. Обратите внимание на condition.await (не .wait).

Для обработки многопоточности я использовал Executors.newCachedThreadPool() создать пул потоков.

Те, кто использует версию Java 7.0 или ниже, могут ссылаться на код, который я использовал здесь, и он работает.

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
    }

}

Не уверен, поможет ли это кому-то еще или нет, но это было ключевым моментом, чтобы исправить мою проблему в ответе пользователя "Tom Hawtin - tacklin" выше:

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

Просто тот факт, что "lock" передается в качестве аргумента в synchronized(), и он также используется в "lock".notifyAll();

Как только я сделал это в тех двух местах, я получил это работает

Для вызова wait() / notify() для объекта он должен находиться внутри синхронизированного блока. Итак, сначала вы должны заблокировать объект, тогда можно будет вызвать эту функцию.

      synchronized(obj)
{
   obj.wait()
}

Для подробного объяснения:https://dzone.com/articles/multithreading-java-and-interviewspart-2

Другие вопросы по тегам