Estoy usando multi-threading en java para mi programa. He ejecutado el hilo con éxito, pero cuando lo estoy usando Thread.wait()
, está tirando java.lang.IllegalMonitorStateException
. ¿Cómo puedo hacer que un hilo espere hasta que sea notificado?
Estoy usando multi-threading en java para mi programa. He ejecutado el hilo con éxito, pero cuando lo estoy usando Thread.wait()
, está tirando java.lang.IllegalMonitorStateException
. ¿Cómo puedo hacer que un hilo espere hasta que sea notificado?
Respuestas:
Debes estar en un synchronized
bloque paraObject.wait()
poder trabajar.
Además, recomiendo mirar los paquetes de concurrencia en lugar de los paquetes de subprocesos de la vieja escuela. Son más seguros y más fáciles de trabajar .
Feliz codificación
EDITAR
Supuse que querías decir Object.wait()
que tu excepción es lo que sucede cuando intentas obtener acceso sin mantener el bloqueo de objetos.
wait
se define en Object
, y no lo es Thread
. El monitor encendido Thread
es un poco impredecible.
Aunque todos los objetos Java tienen monitores, generalmente es mejor tener un bloqueo dedicado:
private final Object lock = new Object();
Puede obtener diagnósticos un poco más fáciles de leer, a un bajo costo de memoria (aproximadamente 2K por proceso) utilizando una clase con nombre:
private static final class Lock { }
private final Object lock = new Lock();
Para / wait
o un objeto, debe mantener el bloqueo con la declaración. Además, necesitará un bucle para verificar la condición de activación (busque un buen texto sobre subprocesos para explicar por qué).notify
notifyAll
synchronized
while
synchronized (lock) {
while (!isWakeupNeeded()) {
lock.wait();
}
}
Notificar:
synchronized (lock) {
makeWakeupNeeded();
lock.notifyAll();
}
Vale la pena entender tanto el lenguaje Java como los java.util.concurrent.locks
bloqueos (y java.util.concurrent.atomic
) al entrar en subprocesos múltiples. Pero use java.util.concurrent
estructuras de datos siempre que pueda.
wait
sí, nunca lo harías notify
. Sin embargo, en los documentos de API para Object.wait
"El subproceso libera la propiedad de este monitor". Entonces, mientras está dentro wait
, es como si estuviera fuera de los synchronized
bloques circundantes (para el mismo objeto, puede haber múltiples synchronized
bloques en el mismo objeto).
Sé que este hilo tiene casi 2 años, pero aún necesito cerrar esto ya que también vine a esta sesión de preguntas y respuestas con el mismo problema ...
Lea esta definición de ilegalMonitorException una y otra vez ...
IllegalMonitorException se genera 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 poseer el monitor especificado.
Esta línea una y otra vez dice, IllegalMonitorException llega cuando ocurre una de las 2 situaciones ...
1> espera en el monitor de un objeto sin tener el monitor especificado.
2> notifique a otros hilos que esperan en el monitor de un objeto sin poseer el monitor especificado.
Algunos podrían haber obtenido sus respuestas ... quien no, entonces verifique 2 declaraciones ...
sincronizado (objeto)
object.wait ()
Si ambos objetos son iguales ... entonces no puede venir ninguna excepción de monitor ilegal.
Ahora lea nuevamente la definición IllegalMonitorException y no la olvidará nuevamente ...
Según sus comentarios, parece que está haciendo algo como esto:
Thread thread = new Thread(new Runnable(){
public void run() { // do stuff }});
thread.start();
...
thread.wait();
Hay tres problemas
Como han dicho otros, obj.wait()
solo se puede invocar si el subproceso actual contiene el bloqueo / mutex primitivo para obj
. Si el hilo actual no mantiene el bloqueo, obtienes la excepción que estás viendo.
La thread.wait()
llamada no hace lo que parece que espera que haga. Específicamente, thread.wait()
no hace que el hilo nominado espere. Más bien hace que el hilo actual espere hasta que otro hilo llame thread.notify()
o thread.notifyAll()
.
En realidad, no existe una forma segura de forzar una Thread
pausa de una instancia si no lo desea. (Lo más cercano que Java tiene a esto es el obsoletoThread.suspend()
método , pero ese método es intrínsecamente inseguro, como se explica en el Javadoc).
Si desea que el recién iniciado se Thread
detenga, la mejor manera de hacerlo es crear una CountdownLatch
instancia y hacer que la llamada de subproceso await()
en el pestillo se detenga. El hilo principal luego llamaría countDown()
al pestillo para permitir que el hilo en pausa continúe.
Ortogonal a los puntos anteriores, el uso de un Thread
objeto como bloqueo / mutex puede causar problemas. Por ejemplo, el javadoc para Thread::join
dice:
Esta implementación utiliza un ciclo de
this.wait
llamadas condicionadasthis.isAlive
. Cuando termina un subprocesothis.notifyAll
, se invoca el método. Se recomienda que las aplicaciones no utilizanwait
,notify
onotifyAll
enThread
casos.
Como no ha publicado el código, estamos trabajando en la oscuridad. ¿Cuáles son los detalles de la excepción?
¿Estás llamando a Thread.wait () desde dentro del hilo o fuera de él?
Pregunto esto porque de acuerdo con el javadoc para IllegalMonitorStateException, es:
Lanzado 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 poseer el monitor especificado.
Para aclarar esta respuesta, esta llamada a esperar en un hilo también arroja 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) { }
}
wait()
.
worker.wait()
línea? Entonces deberías estar sincronizando con el trabajador, no en la cerradura.
Para tratar con IllegalMonitorStateException, debe verificar que todas las invocaciones de la espera, notificar y notificar Todos los métodos se lleven a cabo solo cuando el subproceso de llamada sea el propietario del monitor apropiado . La solución más simple es encerrar estas llamadas dentro de bloques sincronizados. El objeto de sincronización que se invocará en la declaración sincronizada es aquel cuyo monitor debe ser adquirido.
Aquí está el ejemplo simple para entender el concepto de monitor
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();
}
}
}
La llamada Thread.wait () tiene sentido dentro de un código que se sincroniza en el objeto Thread.class. No creo que sea lo que quisiste decir.
Usted pregunta
¿Cómo puedo hacer que un hilo espere hasta que sea notificado?
Solo puede hacer que su hilo actual espere. Cualquier otro hilo solo 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 muy mala elección), es un AFAIK único, por lo que sincronizarlo (excepto los métodos estáticos de Thread) es peligroso.
Tom Hawtin ya explica los detalles de sincronización y espera.
java.lang.IllegalMonitorStateException
significa que está intentando esperar en un objeto en el que no está sincronizado; es ilegal hacerlo.
No estoy seguro de si esto ayudará a alguien más o no, pero esta fue la parte clave para solucionar mi problema en la respuesta anterior del usuario "Tom Hawtin - tacklin":
synchronized (lock) {
makeWakeupNeeded();
lock.notifyAll();
}
Solo el hecho de que el "bloqueo" se pasa como un argumento en sincronizado () y también se usa en "bloqueo" .notifyAll ();
Una vez que lo logré en esos 2 lugares, lo conseguí funcionando
Recibí un IllegalMonitorStateException
tiempo tratando de despertar un hilo en / desde un class
hilo diferente . En java 8
puede utilizar las lock
características de la nueva API de concurrencia en lugar de synchronized
funciones.
Ya estaba almacenando objetos para asynchronous
transacciones websocket en a WeakHashMap
. La solución en mi caso fue también almacenar un lock
objeto en unConcurrentHashMap
para synchronous
respuestas. Tenga en cuenta el condition.await
(no .wait
).
Para manejar el subprocesamiento múltiple, utilicé a Executors.newCachedThreadPool()
para crear un grupo de subprocesos .
Aquellos que usan Java 7.0 o una versión inferior pueden consultar el código que usé 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
}
}