Implementing Native Methods |
Sometimes, a native method contains a critical section of code--a section of code that accesses or modifies a condition variable. Like other critical sections or methods in Java, these native methods have to be synchronized with other methods or code blocks that access the same variable. Synchronization ensures that code running in different threads accesses the condition variable in safety and that the condition variable is in some globally consistent state. Threads of Controlcovers programming with threads. In particular, the page Multithreaded Programscovers issues related to writing programs that contain multiple threads, including how to synchronize them. You should be familiar with the concepts in that section before proceeding here.Three utility functions declared in
monitor.h
allow native methods to interact with Java's monitor mechanism, so that native methods can be thread-safe like regular Java methods. Those functions are:Let's look at an example program that uses these functions to synchronize the execution of two native methods. This example program is a modified version of the Producer/Consumer example found in Synchronizing Threads.
monitorWait()
- Blocks until notification is made on the specified monitor. The
monitorWait()
function is equivalent to Object'swait()
method.monitorNotify()
- Notifies one waiting thread that there is a change of condition on the specified monitor. The
monitorNotify()
function is equivalent to Object'snotify()
method.monitorNotifyAll()
- Notifies all waiting threads that there is a change of condition on the specified monitor. The
monitorNotifyAll()
function is equivalent to Object'snotifyAll()
method.The example program is comprised of these four classes:
Let's look at the new CubbyHole class. The changes made to the CubbyHole class are in bold.
- Producer
- A thread that produces integer values and puts them in a "cubby hole".
- Consumer
- A thread that consumes the values placed in the cubby hole by the producer.
- ProducerConsumerTest
- The main program that starts the producer and consumer threads.
- CubbyHole
- The object where the producer puts its values and the consumer gets them. In the previous, Java-only implementation of this example, the
put()
andget()
methods in this class were synchronized. The program has been modified so thatput()
andget()
are now native methods and use themonitorXXX()
functions to synchronize the producer and consumer threads. This is the only class that needed to be modified.Here's the original version of the CubbyHole class for comparison.class CubbyHole { private int seq; // this is the condition variable. private boolean available = false; public synchronized native int get(); public synchronized native void put(int value); static { try { System.loadLibrary("threadex"); } catch (UnsatisfiedLinkError e) { System.err.println("can't find your library"); System.exit(-1); } } }The first change is that the
get()
andput()
methods are now declarednative
(as well as synchronized) and their implementations have been removed. They are now implemented in C in the fileCubbyHoleImpl.c
.The second change is the addition of a static initializer block. This block of code loads the dynamic library
threadex
that contains the implementations for theget()
andput()
methods.Now, let's look at the new implementations for
get()
andput()
.The logical flow of these methods is identical to the Java implementation of these methods. Note the use oflong CubbyHole_get(struct HCubbyHole *this) { while (unhand(this)->available == 0) { monitorWait(obj_monitor(this)); } unhand(this)->available = 0; monitorNotify(obj_monitor(this)); return unhand(this)->seq; } void CubbyHole_put(struct HCubbyHole *this, long value) { while (unhand(this)->available > 0) { monitorWait(obj_monitor(this)); } unhand(this)->seq = value; unhand(this)->available = 1; monitorNotify(obj_monitor(this)); }monitorWait()
andmonitorNotify()
is identical to the use of thewait()
andnotify()
methods in the Java version.
Implementing Native Methods |