Pregunta

¿Por qué este programa de prueba da como resultado un java.lang.IllegalMonitorStateException ?

public class test {
    static Integer foo = new Integer(1);
    public static void main(String[] args) {
        synchronized(foo) {
            foo++;
            foo.notifyAll();
        }
        System.err.println("Success");
    }
}

Resultado:

Exception in thread "main" java.lang.IllegalMonitorStateException
        at java.lang.Object.notifyAll(Native Method)
        at test.main(test.java:6)
¿Fue útil?

Solución

Ha notado correctamente que se debe llamar a notifyAll desde un bloque sincronizado.

Sin embargo, en su caso, debido al auto-boxeo, el objeto en el que sincronizó no es la misma instancia en la que invocó notifyAll . De hecho, la nueva instancia incrementada de foo todavía está limitada a la pila, y ningún otro subproceso podría bloquearse en una llamada wait .

Puede implementar su propio contador mutable en el que se realiza la sincronización. Dependiendo de su aplicación, también puede encontrar que AtomicInteger satisface sus necesidades.

Otros consejos

También debe desconfiar de bloquear o notificar objetos como String e Integer que pueden ser internados por la JVM (para evitar crear muchos objetos que representen el entero 1 o la cadena " ").

Incrementar el número entero hace que el viejo foo desaparezca y sea reemplazado por un nuevo objeto foo que no esté sincronizado con la variable foo anterior.

Aquí hay una implementación de AtomicInteger que erickson sugirió anteriormente. En este ejemplo, foo.notifyAll (); no produce una excepción java.lang.IllegalMonitorStateException porque el objeto AtomicInteger no se actualiza cuando foo.incrementAndGet (); se ejecuta.

import java.util.concurrent.atomic.AtomicInteger;

public class SynchronizeOnAPrimitive {
    static AtomicInteger foo = new AtomicInteger(1);
    public static void main(String[] args) {
        synchronized (foo) {
            foo.incrementAndGet();
            foo.notifyAll();
        }
        System.out.println("foo is: " + foo);
    }
}

Salida:

foo is: 2

Como ha señalado erickson, el código sin el operador postincremento funciona sin error:

static Integer foo = new Integer(1);

public static void main(String[] args) {
    synchronized (foo) {
        foo.notifyAll();
    }
    System.out.println("Success");
}

salida:

  

Éxito

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top