Java 開発ガイド (Solaris 7 編)

マルチスレッドで安全でないライブラリの使用


注意 - 注意 -

他に回避方法がない場合のみ、以下の方法を使用してください。正規の方法ではないので、十分に注意してプログラミングを行わないと、デッドロックが発生する可能性があります。


-D_REENTRANT を有効にせずにコンパイルされた既存のライブラリを使用する Java アプリケーションを実行しようとすると、以下のような問題が発生します。

JDK 1.1 のようなネイティブスレッドの JVM の場合、libc は、システムコールのエラーコードをスレッド固有の errno に書き込みます。-D REENTRANT フラグを有効にしてコンパイルされていないため、マルチスレッドで安全でないライブラリは、errno を参照するときにグローバル変数の errno を参照します。このため、ライブラリはスレッド固有の errno にアクセスすることができず、失敗したシステムコールに対応する正しい応答を返すことができません。

この問題を根本的に解決するには、ネイティブメソッドによってネイティブコードを使用するマルチスレッドの Java アプリケーションが、マルチスレッドで安全 (または少なくとも errno が安全) なライブラリとリンクされるようにするようにします。

errno が安全でないライブラリをどうしても参照する必要がある場合は、次のような回避方法があります。Java アプリケーションをメインスレッドで開始し、すべての安全でないライブラリに対する呼び出しがメインスレッド経由で行われるようにします。たとえばスレッドが JNI を呼び出す場合、JVM を使って、メインスレッドによって処理される 1 つの待ち行列に、すべての JNI 引数を整列化して追加することができます。このようにして、Java ネイティブインタフェース (JNI、Java Native Interface) を呼び出すスレッドは、自分の代わりにメインスレッドが呼び出しを実行してその結果を返してくれるのを待ちます。

安全でないライブラリに対する呼び出しがメインスレッドからのみ実行される時には、ライブラリ中でも単一スレッドによって処理が行われるので、ロックによって排他処理を行う必要はありません。メインスレッドである程度の並列処理を実現するために、ブロックされない (入出力処理の完了を待たずに復帰する) 呼び出しを実行する場合もありますが、メインスレッドから参照されるのはグローバル変数の errno なので、libc とマルチスレッドで安全でないライブラリの両方も同じ errno を参照することになります。