Неожиданный код в синхронизированном блоке - PullRequest
7 голосов
/ 31 марта 2012

Следующий код Java генерирует следующий байт-код JVM.

Мне любопытно, почему генерируется код от смещения 31 до смещения 36. Ничто в спецификации JLS7 или JVM7 не говорит об этом. Я что-то пропустил?

Даже если я удаляю операторы println, код (смещение 31 - смещение 36) все еще генерируется, только в более раннем месте, так как вызов 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

Ответы [ 2 ]

7 голосов
/ 31 марта 2012

Компилятор добавляет сюда невидимый блок try / catch, чтобы гарантировать освобождение состояния монитора (что задокументировано в спецификациях VM, см. Нижнюю часть поста). Вы можете проверить это с помощью javap -v и посмотреть таблицу исключений:

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

Редактировать: из спецификации JVM :

Обычно компилятор для языка программирования Java гарантирует, что операция блокировки, выполненная инструкцией монитора до выполнения тела синхронизированного оператора соответствует операции разблокировки, осуществляемой monitorexit инструкция всякий раз, когда синхронизированный оператор завершается, будь то завершение нормальное или резкое.

2 голосов
/ 31 марта 2012

Я не знаю, где он находится в JLS, но он должен где-то сказать, что когда выдается исключение, блокировка снимается.Вы можете сделать это с помощью Unsafe.monitorEnter / Exit

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

Я полагаю, что в конце есть таблица блоков перехвата, которая может отсутствовать.

...