2009-10-08 6 views
126

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

+1

Thread.wait() не существует, возможно, это.wait() – Premraj

ответ

137

Чтобы работать, вам необходимо находиться в блоке synchronized для того, чтобы работать Object.wait().

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

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

EDIT

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

+6

'Thread.wait' ?! –

+1

хорошо catch. Я предположил, что он имел в виду Object.wait() и вызван из потока – reccles

+1

Синхронизированный блок объекта, который вы ожидаете. Помогите отредактировать этот ответ, чтобы сделать это более понятным? Благодарю. – Gray

1

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

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

    } 
+0

@CPerkins: Я думаю, вы путаете поток выполнения и объект, который является объектом 'wait()'. –

+0

@ Robert - Возможно, я, но я так не думаю. Если вы запустите экземпляр Thread, а затем попросите его подождать, вы получите исключение IllegalMonitorStateException, которое я пытаюсь описать. – CPerkins

+0

Вы говорите о строке 'worker.wait()'? Затем вы должны синхронизировать работу, а не блокировку. –

39

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 всякий раз, когда сможете.

+3

Я никогда не понимал, как это работает, учитывая, что ожидание и уведомление выполняются как в синхронизированных блоках на одном и том же объекте (блокировка). Так как поток ожидания находится в блоке, не следует ли сделать блок потока уведомлений на строке «synchronized (lock)»? – Brent212

+3

@ Brent212 Для любого метода, кроме 'wait', да, вы никогда не получите« уведомление ». Однако в документах API для 'Object.wait',« поток освобождает владельца этого монитора ». Таким образом, в 'wait' это похоже на то, что он находится вне закрытых блоков« synchronized »(для одного и того же объекта могут быть несколько блоков« synchronized »на одном и том же объекте). –

0

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

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

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

3

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

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

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

18

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

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

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

Эта линия снова и снова говорит, IllegalMonitorException приходит, когда один из 2 ситуации происходит ....

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

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

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

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

Object.wait()

Если оба Объект такие же ... тогда никакое незаконное исключениеMonitorException может прийти.

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

+0

Собственно, это не работает. Я попробовал. Я создаю Runnable, блокирую его (используя синхронизированный блок), и внутри этого блока я запускаю Runnable в UI-потоке (Android), после чего я делаю myRunnable.wait(), и я все еще получаю исключение. – Ted

+0

Excelente информация !! Я выполнял wait() без указания объекта, поэтому он взял экземпляр и синхронизовал другой объект. Теперь я использую otherObject.wait(), и он работает! – Fersca

0

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

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

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

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

0

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

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

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

0

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

}