javaseiten.de   |   Version 0.6
 

4.15. JVM-Befehlssatz: Kurzbeschreibung M

 

 

Befehl Operandenstapel Opcode
monitorenter ..., objectref --> ... 0xc2

Betrete den Monitor für ein bestimmtes Objekt (Synchronisation nebenläufiger Prozesse).

Bezeichner Typ Beschreibung
objectref reference Referenz auf ein Objekt (ein Monitor wird mit diesem Objekt assoziiert).

Um nebenläufige Prozesse synchronisieren zu können wird in Java das Konzept des Monitors verwendet. Innerhalb eines Java-Quelltextes kann die synchronized-Anweisung verwendet verwendet werden, um einen Block von Anweisungen für einen anderen Thread zu sperren. Die Kapselung eines Blocks zur Synchronisation von Threads und die automatische Verwaltung einer zum Block gehörenden Sperre wird als Monitor bezeichnet. Ein Thread kann also einen Monitor sperren (lock) und wieder freigeben (unlock) und nur ein Thread kann die Sperre für einen Monitor besitzen.

Der Compiler erzeugt für eine synchronized-Anweisung die JVM-Befehle monitorenter und monitorexit, die das Betreten und Verlassen des Monitors realisieren. Jedem Objekt kann ein Monitor zugeordnet werden. Der Monitor ergibt sich aus der Objektreferenz objectref, die sich vor der Ausführung von monitorenter auf dem Operandenstapel befindet. Ein Thread, der monitorenter ausführt, beansprucht den Monitor. Falls der Monitor durch einen anderen Thread bearbeitet wird, wartet der ursprüngliche Thread bis der Monitor durch monitorexit wieder freigegeben wurde. Ein Monitor besitzt einen Zähler, der für jeden Thread aufzeichnet, wie oft dieser den Monitor betreten hat.

Beispiel:

Das folgende Beispielprogramm enthält die statische Variable a, die durch zwei Threads erhöht werden kann. Die beiden Threads werden innerhalb der main-Methode gestartet und führen danach die Anweisungen der run-Methode aus. Das Hochzählen der Klassenvariablen a und die Ausgabe ihres Wertes durch die beiden Threads erfolgt asynchron, wenn die beiden Anweisungen innerhalb der synchronized-Blocks nicht gekapselt wären. Ohne Verwendung von synchronized kann der Fall eintreten, dass der eine Thread die Zählvariable um eins erhöht und vor der Kosolenausgabe des Wertes durch einen Scheduler (Steuerungsprogramm) in Wartestellung gesetzt wird. Der zweite Thread wird nun fortgeführt, erhöht a um eins und gibt den Zahlenwert aus. Die Zahlenwerte in der Konsolenausgabe können also Lücken aufweisen (z.B. ..., 377, 378, 380, ..., 655, 379, 656, ...). Um dies zu verhindern wird eine synchronized-Anweisung verwendet. Dazu wird eine Objektreferenz (objectref) benötigt, die durch die Methode getClass festgelegt wird (ein Monitor wird mit einem Objekt assoziiert). Mit Hilfe dieser Methode kann das sogenannte Klassenobjekt clazz erhalten werden, das die Laufzeitklasse für dieses Objekt repräsentiert.

public class Test extends Thread {
  
  static int a = 0;
 
  public void run() {                  public void run();
                                       Code:
    Class clazz = this.getClass();      0: aload_0
                                        1: invokevirtual #2; //Method java/lang/
                                           Object.getClass:()Ljava/lang/Class;
                                        4: astore_1
    while (a < 1000) {                  5: getstatic #3; //Field a:I
                                        8: sipush 1000
                                       11: if_icmpge 48
      synchronized (clazz) {           14: aload_1
                                       15: dup
                                       16: astore_2

                                       17: monitorenter
        a++;                           18: getstatic #3; //Field a:I
                                       21: iconst_1
                                       22: iadd
                                       23: putstatic #3; //Field a:I
        System.out.println(a);         26: getstatic #4; //Field java/lang/
                                           System.out:Ljava/io/PrintStream;
                                       29: getstatic #3; //Field a:I
                                       32: invokevirtual #5; //Method java/io/
                                           PrintStream.println:(I)V
                                       35: aload_2
      }                                36: monitorexit

                                       37: goto 45
                                       40: astore_3
                                       41: aload_2
                                       42: monitorexit
                                       43: aload_3
                                       44: athrow
    }                                  45: goto 5
  }                                    48: return

                                       Exception table:
                                         from   to  target type
                                          18    37    40   any
                                          40    43    40   any

  public static void 
  main(String[] args) {
    Thread t1 = new Test();
    Thread t2 = new Test();
    t1.start();
    t2.start();  
  }
}

Die Anweisung a++ und die Anweisung für die Konsolenausgabe werden auf Bytecodeebene durch die beiden JVM-Befehle monitorenter und monitorexit eingeschlossen. Innerhalb der JVM-Befehlsfolge tritt eine zweite monitorexit-Anweisung bei Bytecodestelle 42 auf. Diese wird verwendet, um einen gesperrten Monitor, auch beim Auftreten einer Ausnahme (Exception), geordnet verlassen zu können. Beim Auftreten einer Ausnahme wird bei Stelle 40 im Bytecode fortgefahren (siehe Exception-Tabelle) und mit athrow wird die Ausnahme an den Aufrufer der zugehörigen Methode weitergegeben.

 

 

monitorexit ..., objectref --> ... 0xc3

Verlasse den Monitor für ein bestimmtes Objekt (Synchronisation nebenläufiger Prozesse).

Bezeichner Typ Beschreibung
objectref reference Referenz auf ein Objekt (ein Monitor wird mit diesem Objekt assoziiert).

Siehe dazu die Beschreibung und das Beispiel von monitorenter.

 

 

multianewarray indexbyte1 indexbyte2 dimensions ..., count1, count2, ..., countn --> ..., arrayref 0xc5

Erzeuge ein neues mehrdimensionales Array.

Bezeichner Typ Beschreibung
indexbyte1 Vorzeichenloses Byte Index im (Laufzeit-)Konstantenpool.
indexbyte2 Vorzeichenloses Byte Index im (Laufzeit-)Konstantenpool.
dimensions Vorzeichenloses Byte Größe (Dimension) des Arrays.
count1 int Länge der 1. Dimension.
count2 int Länge der 2. Dimension.
countn int Länge der n. Dimension.
arrayref reference Referenz auf ein mehrdimensionale Array.

Mit Hilfe der vorzeichenlosen Bytes indexbyte1 und indexbyte2 wird ein Index im (Laufzeit-)Konstantenpool der aktuellen Klasse berechnet: (indexbyte1 << 8) | indexbyte2. Durch die Konstante bei diesem Index kann der Felddeskriptor erhalten werden, der den Typ des mehrdimensionalen Arrays beschreibt (z.B. [[I oder [[Ljava/lang/Integer; für ein mehrdimensionales int- bzw. Integer-Array).

Beispiel:

int[][] i1 = new int[2][2];            0: iconst_2
                                       1: iconst_2
                                       2: multianewarray #2, 2; //class "[[I"
                                       6: astore_1
i1[0][1] = 3;                          7: aload_1
                                       8: iconst_0
                                       9: aaload
                                      10: iconst_1
                                      11: iconst_3
                                      12: iastore
Integer[][] i2 = new Integer[4][4];   13: iconst_4
                                      14: iconst_4
                                      15: multianewarray #3, 2; 
                                          //class "[[Ljava/lang/Integer;"
                                      19: astore_2
i2[2][3] = new Integer(4);            20: aload_2
                                      21: iconst_2
                                      22: aaload
                                      23: iconst_3
                                      24: new #4; //class java/lang/Integer
                                      27: dup
                                      28: iconst_4
                                      29: invokespecial #5; //Method java/lang/
                                          Integer."<init>":(I)V
                                      32: aastore

 

 

 

Diese Seite nutzt Google-Dienste - siehe dazu Datenschutz.

Copyright © 2006, 2007 Harald Roeder