ネイティブメソッドを実装する |
ネイティブメソッドがコードのクリティカルセクション、すなわち、条件変数へのアクセスやその変更を行うセクションを含んでいる場合がある。Java の他のクリティカルなセクションやメソッドのように、このようなネイティブメソッドも、同じ変数を アクセスする他のメソッドやコードブロックと同期をとる必要がある。同期により、 異なるスレッドで動作するコードが安全に条件変数をアクセスし、条件変数が全体的に一貫した状態を保てるように保証される。スレッドを使ったプログラミングについては、スレッドのコントロール で説明されている。特に、マルチスレッド化されたプログラムのページで、複数スレッドの同期のとり方など、複数スレッドを含んだプログラムの記述に関連した項目を解説している。この先に進む前に、それらの節で述べられている概念をよく理解する必要がある。この節では、読者がそれらの節で述べられている概念や技術用語を理解していることを前提に説明を進める。ネイティブメソッドが Java のモニタ機構と相互作用できるようにする 3 つのユーティリティ関数が用意されている。これにより、ネイティブメソッドは通常の Java メソッドのようにスレッド安全となれるのである。これらの関数を次に示す。
monitorWait()
- この関数は指定のモニタ上で通知がなされるまでブロックする。
monitorWait()
関数は Java 側での Object のwait()
メソッドと同等である。monitorNotify()
- この関数は指定のモニタ上で条件に変化が生じたことを 1 つの待機中スレッド に通知する。
monitorNotify()
関数は Java 側での Object のnotify()
メソッドと同等である。monitorNotifyAll()
- この関数は指定のモニタ上で条件に変化が生じたことをすべての待機中スレッ ドに通知する。
monitorNotifyAll()
関数は Java 側での Object のnotifyAll()
メソッドと同等である。これらの関数を使用して 2 つのネイティブメソッドの実行を同期するプログラム例 を見てみる。このプログラム例はスレッドの同期にある。
プログラム例は次の 4 つのクラスで構成されている。
- Producer
- 整数値を作り出し、小さい整理棚 (cubby hole) に納めるスレッド
- Consumer
- producer によって cubby hole に配置された値を使用するスレッド
- ProducerConsumerTest
- producer と consumer スレッドを始動させるメインプログラム
- Cubby Hole
- producer が値を入れ、consumer がその値を取り出すオブジェクト。この例は 、以前の Java のみの実装では、 このクラスの
put()
およびget()
メソッドが同期していた。今回のプログラムは、put()
およびget()
をネイティブメソッドとし、すでに説明したmonitorXXX()
関数を使用して producer および consumer スレッドを同期するように変更された。変更が必要だったのはこのクラスだけである。新規の CubbyHole クラスを次に示す。CubbyHole クラスに加えられた変更部分は太字で示してある。
比較のためにCubbyHole クラスの オリジナルバージョン を示す。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); } } }最初の変更は、
get()
とput()
メソッド が (同期をとることのほかに)native
で宣言されていることと、それ らの実装が削除されていることである。実装はCubbyHoleImpl.c
ファイルで C 言語によって行われる。2 番目の変更は、静的イニシャライザブロックの追加である。このコードブロックは
get()
およびput()
メソッドの実装を含んだ動的ライブラリthreadex
をロードする。ここで、
get()
とput()
の新しい実装を見てみよう。論理的な流れはこれらのメソッドを Java で実装した場合と同一である。long 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()
およびmonitorNotify()
を使用することが、Java バージョンでwait()
およびnotify()
メ ソッドを使用することと同じであることに注意する。
ネイティブメソッドを実装する |