When we write synchronized(some_object){}
we can see two JVM instructions monitorenter/monitorexit
issued as the byte code.
When we write synchronized(some_object){some_object.wait()}
i would expect to see special JVM instructions like wait
, but none -- instead wait/notify
are implemented as native C functions.
Why there is such inconsistency (either have them all as JNI or as java byte code)? Was there a particular (historical) reason or it is just a matter of taste?
Context: i am interested in this because having all monitorenter/monitorexit/wait/notify
in the bytecode would allow 'JavaByteCode program correctness verifiers that do not handle JNI' to verify concurrent Java programs that do not use JNI. Currently, such hypothetical tool has to workaround wait/notify.
There is no need for a verification program to deal with JNI as the semantics of wait
and notify
calls are well-specified. That’s not different to dedicated bytecode instructions. The same applies to how the hot spot optimizer deals with a lot of well known method invocations, which may include wait
and notify
. It does not necessarily generate a costly JNI invocation but rather generate code performing these low-level operations directly. Methods handled this way are called intrinsic methods (see also here or here.
There are so many, that you couldn’t call it bytecode anymore if you tried to reserve an opcode for each of them. Further, which methods are handled this way, depends on the actual JVM implementation and the hardware architecture on which it runs. It might also change between versions so there is no sense to carve it in stone by defining bytecode instructions for them.
You wrote “Currently, such hypothetical tool has to workaround wait/notify”. In fact, handling these special methods is not a work-around. It’s what such an audit tool has to do with a lot of methods like these declared in Lock
and Condition
which have similar threading-related semantics but there are also a lot of other well-known concurrency tools nowadays which have to be handled.
The exact decision to create monitorenter
and monitorexit
instructions but make wait
and notify
methods on Object
is historical (it dates back over 20 years ago). Today, the decision might look different if the developers had to make it again. But I guess it would rather go into the direction to make even monitorenter
and monitorexit
special methods that are invoked under the hood rather than bytecode instructions. First, they are not the only thread synchronization tool anymore. Second, it’s how most of the new feature were added in the recent JVMs, preferably as method, even if it’s expected to be intrinsified by most, if not all, implementations.