java - ¿Por qué notifyAll() genera IllegalMonitorStateException cuando se sincroniza en Integer?
synchronization (4)
¿Por qué este programa de prueba da como resultado una 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)
Ha notado correctamente que se debe llamar a notifyAll
desde un bloque sincronizado.
Sin embargo, en su caso, debido al auto-boxing, el objeto que sincronizó no es la misma instancia que invocó a notifyAll
. De hecho, la nueva instancia de foo
incrementada todavía está confinada a la pila, y no es posible bloquear ninguna otra cadena en una llamada de 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.
También debe desconfiar de bloquear o notificar objetos como String e Integer que la JVM pueda internar (para evitar la creación de muchos objetos que representen el entero 1 o la cadena "").
Al aumentar el número entero, el antiguo foo desaparece y se reemplaza 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 Erickson ha notado, el código sin el operador postincrement 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