2012-03-31 20 views
7

El siguiente código Java genera el siguiente código de byte JVM.Código inesperado en el bloque sincronizado

Tengo curiosidad de por qué se genera el código del desplazamiento 31 al desplazamiento 36. Nada en la especificación JLS7 o JVM7 habla de esto. ¿Yo me perdí algo?

Incluso si elimino las instrucciones println, el código (offset 31 a offset 36) aún se genera, solo en una ubicación anterior, ya que se ha eliminado la llamada println.

// Java code 
    void testMonitor() { 
     Boolean x = new Boolean(false); 
     synchronized(x) { 
      System.out.println("inside synchronized"); 
      System.out.println("blah"); 
     }; 
     System.out.println("done"); 
    } 


// JVM bytecode 
    Offset Instruction  Comments (Method: testMonitor) 
    0  new 42   (java.lang.Boolean) 
    3  dup 
    4  iconst_0 
    5  invokespecial 44 (java.lang.Boolean.<init>) 
    8  astore_1   (java.lang.Boolean x) 
    9  aload_1   (java.lang.Boolean x) 
    10  dup 
    11  astore_2 
    12  monitorenter 
    13  getstatic 15  (java.lang.System.out) 
    16  ldc 47   (inside synchronized) 
    18  invokevirtual 23 (java.io.PrintStream.println) 
    21  getstatic 15  (java.lang.System.out) 
    24  ldc 49   (blah) 
    26  invokevirtual 23 (java.io.PrintStream.println) 
    29  aload_2 
    30  monitorexit 
    31  goto 37 
    34  aload_2 
    35  monitorexit 
    36  athrow 
    37  getstatic 15  (java.lang.System.out) 
    40  ldc 51   (done) 
    42  invokevirtual 23 (java.io.PrintStream.println) 
    45  return 

Respuesta

2

no sé donde está en el JLS, pero hay que decir en alguna parte que cuando se produce una excepción, un bloqueo se libera. Usted puede hacer esto con Unsafe.monitorEnter/Salir

void testMonitor() { 
    Boolean x = new Boolean(false); 
    theUnsafe.monitorEnter(x); 
    try { 
     System.out.println("inside synchronized"); 
     System.out.println("blah"); 
    } catch(Throwable t) { 
     theUnsafe.monitorExit(x); 
     throw t; 
    }; 
    theUnsafe.monitorExit(x); 
    System.out.println("done"); 
} 

Creo que hay una tabla de bloque catch al final es posible que falte.

+0

Hola Peter, tu respuesta no responde a la pregunta: "Tengo curiosidad por saber por qué se genera el código ..." o incluso "¿Extrañé algo?". Gracias por su participación. – chuacw

+0

El código se genera porque tiene que haber código para liberar el bloqueo, ver mi ejemplo. Te perdiste mi intento de explicar. ;) –

+0

La explicación de Rene es mejor. Además, tenga en cuenta que no pedí una forma alternativa. Gracias de cualquier manera. – chuacw

7

El compilador agrega un bloque try/catch invisible aquí, para garantizar que se libere el estado del monitor (que está documentado en las especificaciones de VM, ver la parte inferior de la publicación). Esto se puede comprobar mediante el uso de javap -v y mirar la tabla de excepciones:

void testMonitor(); 
    Code: 
    Stack=3, Locals=3, Args_size=1 
    0: new #15; //class java/lang/Boolean 
    3: dup 
    4: iconst_0 
    5: invokespecial #17; //Method java/lang/Boolean."<init>":(Z)V 
    8: astore_1 
    9: aload_1 
    10: dup 
    11: astore_2 
    12: monitorenter 
    13: getstatic #20; //Field java/lang/System.out:Ljava/io/PrintStream; 
    16: ldc #26; //String inside synchronized 
    18: invokevirtual #28; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 
    21: getstatic #20; //Field java/lang/System.out:Ljava/io/PrintStream; 
    24: ldc #34; //String blah 
    26: invokevirtual #28; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 
    29: aload_2 
    30: monitorexit 
    31: goto 37 
    34: aload_2 
    35: monitorexit 
    36: athrow 
    37: getstatic #20; //Field java/lang/System.out:Ljava/io/PrintStream; 
    40: ldc #36; //String done 
    42: invokevirtual #28; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 
    45: return 
    Exception table: 
    from to target type 
    13 31 34 any 
    34 36 34 any 

Editar: Desde el JVM specs:

Normalmente, un compilador para el lenguaje de programación Java asegura que la operación de bloqueo implementado por una instrucción monitorenter ejecutada antes de la ejecución del cuerpo de la instrucción sincronizada es emparejada por una operación de desbloqueo implementada por una instrucción monitorexit cuando se completa la instrucción sincronizada, ya sea la finalización es normal o abrupta.

+0

Hola Rene, gracias. – chuacw

+0

De nada ;-) – Neet

Cuestiones relacionadas