IllegalMonitorStateException on wait () call


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

10 139

10 ответов:

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

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

удачи в кодировании.

EDIT

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

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

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

private final Object lock = new Object();

вы можете получить немного легче читать диагностику, при небольшой стоимости памяти (около 2K за процесс) с помощью именованного класса:

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 лет, но все равно нужно закрыть это, так как я также пришел к этому сеансу Q/A с той же проблемой...

пожалуйста, прочитайте это определение illegalMonitorException снова и снова...

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

эта строка снова и снова говорит, IllegalMonitorException приходит, когда происходит одна из двух ситуаций....

1> Ожидание на мониторе объекта без владения указанным монитором.

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

некоторые, возможно, получили свои ответы... кто все нет, то проверьте 2 заявления....

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

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

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

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

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

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

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

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

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

вы вызываете поток.подождите () внутри потока или вне его?

Я спрашиваю это, потому что в соответствии с 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 () вызов имеет смысл внутри кода, который синхронизируется в потоке.объект класса. Я не думаю, что это то, что вы имели в виду.
Вы спросите

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

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

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

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

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

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

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

Я уже хранил объекты для asynchronous транзакции websocket в A WeakHashMap. Решение в моем случае было также магазине

те, кто использует 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
    }

}

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

вот простой пример для того, чтобы понять концепцию монитора

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