Вызов IllegalMonitorStateException при вызове wait() - программирование

Вызов IllegalMonitorStateException при вызове wait()

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

4b9b3361

Ответ 1

Вам нужно быть в блоке synchronized, чтобы Object.wait() работал.

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

Счастливое кодирование.

ИЗМЕНИТЬ

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

Ответ 2

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 locks (и java.util.concurrent.atomic). Но используйте java.util.concurrent структуры данных, когда сможете.

Ответ 3

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

Прочитайте это определение незаконногоMonitorException снова и снова...

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

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

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

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

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

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

Object.wait()

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

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

Ответ 4

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

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().

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

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

Ответ 5

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

Вы вызываете 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) { }

    }

Ответ 6

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

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

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

Ответ 7

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

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

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

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

Ответ 8

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

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

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

Ответ 9

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

}

Ответ 10

(За сообщение, ответившее @Tom Hawtin)

Как вы можете создать экземпляр блокировки?()

  private static final class Lock { }
  private final Object lock = new Lock();//This is incorrect.

Это

  private  final Object lck = new ReentrantLock();

Как вы можете создать экземпляр блокировки? Его интерфейс..!!!