当我们编写synchronized(some_object){}
时,我们可以看到两个JVM指令monitorenter/monitorexit
作为字节代码发出。
当我们写synchronized(some_object){some_object.wait()}
时,我希望看到像wait
这样的特殊JVM指令,但是没有 - 而wait/notify
被实现为本机C函数。
为什么存在这样的不一致(要么将它们全部作为JNI还是作为java字节代码)?是否存在特定(历史)原因或仅仅是品味问题?
上下文:我对此感兴趣,因为字节码中包含所有monitorenter/monitorexit/wait/notify
将允许JavaByteCode程序正确性验证程序无法处理JNI'验证不使用JNI的并发Java程序。目前,这种假设工具必须解决等待/通知问题。
答案 0 :(得分:6)
我希望看到像
这样的特殊JVM指令wait
我不会。这在我看来是不一致的 - 在源代码中,你只是调用一个方法,所以你只是在字节码中调用一个方法也是有意义的。否则,编译器必须具备这些方法的特殊知识,而目前还不具备这些方法。
可以说,monitorenter
和monitorexit
通过方法调用实现更有意义(例如,在.NET中)。某些方法总是本机的并且与JVM本身密切相关 - 我没有看到任何不合理的东西,我不希望每个方法都通过单独的字节码操作来实现。但是,由于synchronized
具有支持它的特殊字节码,我没有太多很多问题,因为它是一种语言结构(如try/catch/finally
),而不仅仅是常规方法调用
答案 1 :(得分:4)
由于wait
和notify
调用的语义已明确指定,因此无需验证程序来处理JNI。这与专用字节码指令没有什么不同。这同样适用于热点优化器如何处理许多众所周知的方法调用,其中可能包括wait
和notify
。它不一定会生成昂贵的JNI调用,而是生成直接执行这些低级操作的代码。以这种方式处理的方法称为intrinsic methods(另请参阅here或here。
如果您尝试为每个代码保留操作码,那么您就不能再将其称为字节代码了。此外,以这种方式处理哪些方法取决于实际的JVM实现以及它运行的硬件体系结构。它也可能在不同版本之间发生变化,因此通过为它们定义字节码指令没有任何意义可以将它刻画成石头。
您写道“目前,此类假设工具必须解决等待/通知”。事实上,处理这些特殊方法并非一种解决方法。正是这样的审计工具与许多方法有关,比如Lock
和Condition
中声明的那些具有类似线程相关语义的方法,但现在还有很多其他众所周知的并发工具必须处理。
创建monitorenter
和monitorexit
说明但在wait
上制作notify
和Object
方法的确切决定是历史性的(可追溯到20多年前) )。今天,如果开发者不得不重新做出决定,那么决定可能会有所不同。但我想它更倾向于使偶数monitorenter
和monitorexit
在引擎盖下调用的特殊方法而不是字节码指令。首先,它们不再是唯一的线程同步工具。其次,它是大多数新功能在最近的JVM中添加的方式,最好是作为方法,即使它预计会被大多数(如果不是全部)实现所吸引。