java synchronization notify illegalmonitorstateexcep

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