Previous | Next | Trail Map | Integrating Native Methods into Java
Programs | ネイティブメソッドを実装する


ネイティブメソッドとスレッドの同期

ネイティブメソッドがコードのクリティカルセクション、すなわち、条件変数へのアクセスやその変更を行うセクションを含んでいる場合がある。Java の他のクリティカルなセクションやメソッドのように、このようなネイティブメソッドも、同じ変数を アクセスする他のメソッドやコードブロックと同期をとる必要がある。同期により、 異なるスレッドで動作するコードが安全に条件変数をアクセスし、条件変数が全体的に一貫した状態を保てるように保証される。スレッドを使ったプログラミングについては、スレッドのコントロール(in the Writing Java Programs trail) で説明されている。特に、マルチスレッド化されたプログラム(in the
Writing Java Programs trail)のページで、複数スレッドの同期のとり方など、複数スレッドを含んだプログラムの記述に関連した項目を解説している。この先に進む前に、それらの節で述べられている概念をよく理解する必要がある。この節では、読者がそれらの節で述べられている概念や技術用語を理解していることを前提に説明を進める。

ネイティブメソッドが Java のモニタ機構と相互作用できるようにする 3 つのユーティリティ関数が用意されている。これにより、ネイティブメソッドは通常の Java メソッドのようにスレッド安全となれるのである。これらの関数を次に示す。

monitorWait()
この関数は指定のモニタ上で通知がなされるまでブロックする。monitorWait() 関数は Java 側での Object の wait() メソッドと同等である。
monitorNotify()
この関数は指定のモニタ上で条件に変化が生じたことを 1 つの待機中スレッド に通知する。monitorNotify() 関数は Java 側での Object のnotify() メソッドと同等である。
monitorNotifyAll()
この関数は指定のモニタ上で条件に変化が生じたことをすべての待機中スレッ ドに通知する。monitorNotifyAll() 関数は Java 側での Object のnotifyAll() メソッドと同等である。

これらの関数を使用して 2 つのネイティブメソッドの実行を同期するプログラム例 を見てみる。このプログラム例はスレッドの同期(in the
Writing Java Programs trail)にある。

プログラム例は次の 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 クラスに加えられた変更部分は太字で示してある。

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);
        }
    }
}

比較のためにCubbyHole クラスの オリジナルバージョン を示す。

最初の変更は、 get()put() メソッド が (同期をとることのほかに) native で宣言されていることと、それ らの実装が削除されていることである。実装は CubbyHoleImpl.c ファイルで C 言語によって行われる。

2 番目の変更は、静的イニシャライザブロックの追加である。このコードブロックはget() および put() メソッドの実装を含んだ動的ライブラリ threadex をロードする。

ここで、get()put() の新しい実装を見てみよう。

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));
}

論理的な流れはこれらのメソッドを Java で実装した場合と同一である。monitorWait() および monitorNotify() を使用することが、Java バージョンで wait() および notify() メ ソッドを使用することと同じであることに注意する。


Previous | Next | Trail Map | Integrating Native Methods into Java
Programs | ネイティブメソッドを実装する