4

为类似 Java 的语言编写自己的编译器时,我无法编译synchronized blocks. 我想出了以下想法将它们简化为try-finally块:

synchonized (obj) {
     statements...
}

可以换成

Object _lock = obj
_monitorEnter(lock)
try {
    statements...
}
finally {
    _monitorExit(lock)
}

其中_monitorEnter_monitorExit表示MONITORENTERMONITOREXIT说明。

我对如何synchronized编译的这个假设是正确的,还是我遗漏了什么?

编辑

我的实现以前在正文中对returnthrow语句进行了一些特殊处理。基本上,它会在每个or指令之前手动加载所有lock变量和它们。这是由块处理,还是我仍然需要这些检查?MONITOREXIT*RETURNTHROWfinally

4

2 回答 2

5

你的假设是正确的。synchronizedJava 语言中的块是用monitorentermonitorexit指令实现的。您可以在此处查看 JVM 规范详细信息。

Java 虚拟机中的同步是通过监视器进入和退出来实现的,无论是显式的(通过使用 monitorenter 和 monitorexit 指令)还是隐式的(通过方法调用和返回指令)。

编译器生成的字节码将处理synchronized体内抛出的所有异常,因此您的 try-finally 方法在这里可以正常工作。

声明规范finally并没有说明发布监视器的任何内容。synchronized第一个链接中提供的示例显示了包装在块中的简单方法的字节码。如您所见,处理任何可能的异常以确保执行 monitorexit 指令。您应该在编译器中实现相同的行为(编写将在 finally 语句中释放监视器的代码)。

void onlyMe(Foo f) {
    synchronized(f) {
        doSomething();
    }
}

Method void onlyMe(Foo)
0   aload_1             // Push f
1   dup                 // Duplicate it on the stack
2   astore_2            // Store duplicate in local variable 2
3   monitorenter        // Enter the monitor associated with f
4   aload_0             // Holding the monitor, pass this and...
5   invokevirtual #5    // ...call Example.doSomething()V
8   aload_2             // Push local variable 2 (f)
9   monitorexit         // Exit the monitor associated with f
10  goto 18             // Complete the method normally
13  astore_3            // In case of any throw, end up here
14  aload_2             // Push local variable 2 (f)
15  monitorexit         // Be sure to exit the monitor!
16  aload_3             // Push thrown value...
17  athrow              // ...and rethrow value to the invoker
18  return              // Return in the normal case
Exception table:
From    To      Target      Type
4       10      13          any
13      16      13          any
于 2016-01-23T13:14:45.347 回答
0

正如您所猜测的,Java 编译器将同步块编译为类似于 try-finally 的东西。但是,有一个细微的区别——异常处理会捕获抛出的异常monitorexit并无限循环尝试释放锁。在 Java 中没有办法像这样指定控制流。

于 2016-01-23T15:09:24.777 回答