2009-10-08 20 views
126

Estoy usando multi-threading en java para mi programa. He corrido satisfactoriamente el hilo, pero cuando estoy usando Thread.wait(), arroja java.lang.IllegalMonitorStateException. ¿Cómo puedo hacer que un hilo espere hasta que se lo notifiquen?IllegalMonitorStateException en wait() call

+1

Thread.wait() no existe, podría ser this.wait() – Premraj

Respuesta

137

Debe estar en un bloque synchronized para que Object.wait() funcione.

Además, recomiendo ver los paquetes de simultaneidad en lugar de los paquetes de subprocesamiento de la vieja escuela. Son más seguros y mucho menos easier to work with.

Happy coding.

EDITAR

Supuse que quería decir Object.wait() como su excepción es lo que sucede cuando se intenta acceder sin sostener bloquean los objetos.

+6

'Thread.wait' ?! –

+1

buena captura. Supuse que se refería a Object.wait() y llamó desde un hilo – reccles

+1

Un bloque sincronizado en el objeto que está esperando. ¿Te importa editar esta respuesta para que sea un poco más clara? Gracias. – Gray

1

Como no ha publicado el código, estamos trabajando en la oscuridad. ¿Cuáles son los detalles de la excepción?

¿Está llamando a Thread.wait() desde el hilo o fuera de él?

lo pregunto porque de acuerdo con el Javadoc para IllegalMonitorStateException, es:

Lanzado para indicar que un mensaje ha tratado de esperar en el monitor de un objeto o para notificar a otros hilos que esperan en el monitor de un objeto sin ser dueño del monitor especificado.

Para aclarar esta respuesta, esta llamada a esperar en un hilo también lanza IllegalMonitorStateException, a pesar de ser llamado desde dentro de un bloque sincronizado:


    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: Creo que estás confundiendo el hilo de ejecución y el objeto que es el objetivo de 'wait()'. –

+0

@Robert - Quizás sí, pero no lo creo. Si comienza una instancia Thread y luego le pide que espere, obtendrá IllegalMonitorStateException, que es lo que estaba tratando de describir. – CPerkins

+0

¿Estás hablando de la línea 'worker.wait()'? Entonces deberías estar sincronizando con el trabajador, no con el candado. –

39

wait se define en Object, y no se Thread. El monitor en Thread es un poco impredecible.

A pesar de todos los objetos de Java tienen monitores, generalmente es mejor tener una cerradura dedicado:

private final Object lock = new Object(); 

Puede obtener un poco más fácil de leer el diagnóstico, en un pequeño coste de memoria (alrededor de 2K por proceso) mediante el uso de una clase llamada:

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

con el fin de wait o notify/notifyAll un objeto, tiene que ser la celebración de la cerradura con la declaración synchronized. Además, necesitará un bucle while para verificar la condición de activación (busque un buen texto en el subproceso para explicar por qué).

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

a notificar:

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

Vale la pena llegar a comprender tanto el lenguaje Java y java.util.concurrent.locks cerraduras (y java.util.concurrent.atomic) al entrar en multihilo.Pero use java.util.concurrent estructuras de datos siempre que pueda.

+3

Nunca he entendido cómo funciona esto, dado que la espera y la notificación están ambas en bloques sincronizados en el mismo objeto (bloqueo). Como el hilo de espera está en el bloque, ¿no debería eso hacer que el bloque de hilos de notificación esté en la línea "sincronizada (bloqueo)"? – Brent212

+3

@ Brent212 Para cualquier otro método que no sea 'wait', sí, nunca llegarás a' notify'. Sin embargo, en los documentos API para 'Object.wait'," El hilo libera la propiedad de este monitor ". Por lo tanto, mientras está "esperando" es como si estuviera fuera de los bloques 'sincronizados' que lo contienen (para el mismo objeto, puede haber múltiples bloques' sincronizados' en el mismo objeto). –

0

La llamada a Thread.wait() tiene sentido dentro de un código que se sincroniza en el objeto Thread.class. No creo que sea lo que querías decir.
Usted pregunta

¿Cómo puedo hacer una espera hasta que el hilo se notificará?

Solo puede esperar el hilo actual. Cualquier otro hilo se puede pedir suavemente que espere, si está de acuerdo.
Si desea esperar alguna condición, necesita un objeto de bloqueo: el objeto Thread.class es una opción muy mala: es un AFAIK de singleton, por lo que sincronizarlo (excepto para los métodos estáticos de subprocesos) es peligroso.
Los detalles para la sincronización y la espera ya han sido explicados por Tom Hawtin. java.lang.IllegalMonitorStateException significa que está intentando esperar un objeto en el que no está sincronizado; es ilegal hacerlo.

3

Sobre la base de sus comentarios Parece que usted está haciendo algo como esto:

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

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

hay dos problemas. En primer lugar, como han dicho otros, obj.wait() solo se puede invocar si el hilo actual contiene el mutex primitivo para obj. Si el hilo actual no contiene el mutex, obtienes la excepción que estás viendo.

El segundo (más importante) problema es que thread.wait() no hace lo que parece estar esperando que haga. Específicamente, thread.wait()no hace causa que el subproceso designado espere. Más bien ocasiona que el hilo actual espere hasta que otro hilo llame a thread.notify() o thread.notifyAll().

En realidad, no existe una forma segura de forzar a una instancia de subproceso a pausar si no lo desea. (El más cercano que Java tiene que esta es la obsoleta Thread.suspend() método, pero ese método es inherentemente insegura, como se explica en el Javadoc.)

Si desea que el hilo recién iniciada para hacer una pausa, la mejor manera de hacerlo es para crear una instancia de CountdownLatch y hacer que el hilo llame al await() en el pestillo para pausarlo. El hilo principal llamaría al countDown() en el pestillo para permitir que el hilo pausado continúe.

18

Sé que este hilo es de casi 2 años, pero todavía tienen que cerrar esto ya que también vine a este Q/A con mismo problema ...

Lea esta definición de illegalMonitorException una y otra vez ..

IllegalMonitorException se emite para indicar que un subproceso ha intentado esperar en el monitor de un objeto o para notificar a otros subprocesos que esperan en el monitor de un objeto sin ser propietarios del monitor especificado.

Esta línea dice una y otra vez, IllegalMonitorException viene cuando se produce uno de los 2 ....

situación

1> esperar en el monitor de un objeto sin tener que poseer el monitor especificado.

2> notificar a otros subprocesos que esperan en el monitor de un objeto sin ser propietarios del monitor especificado.

Algunos podrían haber conseguido sus respuestas ... que todo no, entonces por favor revise las declaraciones 2 ....

sincronizada (objeto)

Object.wait()

Si ambos objeto son lo mismo ... entonces no se puede obtener la excepción illegalMonitorException.

Ahora, de nuevo, lea la definición IllegalMonitorException y que no se olvidará de nuevo ...

+0

En realidad, eso no funciona. Lo intenté Creo un Runnable, lo encierro (usando el bloque sincronizado) y dentro de ese bloque ejecuto Runnable en el UI-thread (Android) y luego hago myRunnable.wait(), y aún obtengo la excepción. – Ted

+0

Excelente explicación !! Estaba haciendo wait() sin especificar el objeto, por lo que tomó la instancia y la sincronización en otro objeto. Ahora estoy usando otherObject.wait() y funciona! – Fersca

0

No estoy seguro si esto va a ayudar a otra persona a cabo o no, pero esta fue la pieza clave para solucionar mi problema en el usuario "Tom Hawtin - tacklin " 's respuesta anterior:

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

Sólo el hecho de que el 'bloqueo' se pasa como un argumento en sincronizado (es) y que también se utiliza en 'bloquear' .notifyAll();

Una vez lo hice en esos 2 lugares a los que tiene que trabajar

0

recibí una IllegalMonitorStateException al tratar de despertar un hilo en/desde un class/subproceso diferente. En java 8 puede usar las funciones lock features of the new Concurrency APIen su lugar de synchronized.

Ya estaba almacenando objetos para transacciones de websocket asynchronous en un WeakHashMap. La solución en mi caso también fue store a lock object in a ConcurrentHashMap para synchronous respuestas. Notacondition.await (no .wait).

Para manejar el multi-threading utilicé un Executors.newCachedThreadPool() para crear un thread pool.

0

Los que están utilizando la versión de Java 7.0 o inferior pueden referir el código que utilicé aquí y funciona.

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 
    } 

}