Each Java object has an implicit monitor.
The Java VM uses the instruction monitorenter to acquire
and lock a monitor, and monitorexit to release it.
The corresponding CNI macros are JvMonitorEnter and
JvMonitorExit (JNI has similar methods MonitorEnter
and MonitorExit).
The Java source language does not provide direct access to these primitives.
Instead, there is a synchronized statement that does an
implicit monitorenter before entry to the block,
and does a monitorexit on exit from the block.
Note that the lock has to be released even when the block is abnormally
terminated by an exception, which means there is an implicit
try finally surrounding synchronization locks.
From C++, it makes sense to use a destructor to release a lock. CNI defines the following utility class:
class JvSynchronize() {
jobject obj;
JvSynchronize(jobject o) { obj = o; JvMonitorEnter(o); }
~JvSynchronize() { JvMonitorExit(obj); }
};
So this Java code:
synchronized (OBJ)
{
CODE
}
might become this C++ code:
{
JvSynchronize dummy (OBJ);
CODE;
}
Java also has methods with the synchronized attribute.
This is equivalent to wrapping the entire method body in a
synchronized statement.
(Alternatively, an implementation could require the caller to do
the synchronization. This is not practical for a compiler, because
each virtual method call would have to test at run-time if
synchronization is needed.) Since in gcj
the synchronized attribute is handled by the
method implementation, it is up to the programmer
of a synchronized native method to handle the synchronization
(in the C++ implementation of the method).
In otherwords, you need to manually add JvSynchronize
in a native synchornized method.