2012-03-31 9 views
7

Il seguente codice Java genera il seguente codice byte JVM.Codice imprevisto nel blocco sincronizzato

Sono curioso perché viene generato il codice dall'offset 31 all'offset 36. Nulla nelle specifiche JLS7 o JVM7 parla di questo. Mi sono perso qualcosa?

Anche se rimuovo le istruzioni println, il codice (offset 31 per offset 36) viene ancora generato, solo in una posizione precedente, poiché la chiamata println è stata rimossa.

// 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 

risposta

2

non so dove si trova nel JLS, ma deve dire da qualche parte che quando viene generata un'eccezione, un blocco viene rilasciato. È possibile farlo con Unsafe.monitorEnter/Uscita

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"); 
} 

Credo che ci sia un tavolo blocco catch alla fine si può mancare.

+0

Ciao Peter, la tua risposta non risponde alla domanda: "Sono curioso perché il codice ... viene generato" o addirittura "Mi sono perso qualcosa?". Grazie per la tua partecipazione però. – chuacw

+0

Il codice viene generato perché deve esserci codice per rilasciare il blocco, vedere il mio esempio. Hai perso il mio tentativo di spiegare. ;) –

+0

La spiegazione di Rene è migliore. Inoltre, nota che non ho chiesto un modo alternativo. Grazie comunque. – chuacw

7

Il compilatore aggiunge un blocco try/catch invisibile qui, per garantire che lo stato del monitor venga rilasciato (che è documentato nelle specifiche della VM, vedere in fondo al post). È possibile verificare questo utilizzando javap -v e guardare la tabella eccezione:

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 

Edit: Dal JVM specs:

Normalmente, un compilatore per il linguaggio di programmazione Java assicura che l'operazione di blocco attuato da un'istruzione monitorenter eseguita prima dell'esecuzione del corpo dell'istruzione sincronizzata è abbinata a un'operazione di sblocco implementata da un'istruzione monitorexit ogni volta che l'istruzione sincronizzata viene completata, siaIl completamentoè normale o brusco.

+0

Ciao Rene, grazie. – chuacw

+0

Prevedibile ;-). – Neet