JDK 1.1 開発ガイド (Solaris 編)

Solaris に固有の問題

以降で説明するように、いくつかの問題は Solaris に固有です。

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


注意 - 注意 -

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


-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 を参照することになります。

interrupt() メソッド

このメソッドには現在のところ特別に便利な機能はないので、一般的には推奨していません。Java 言語仕様 (JLS、Java Language Specification) では、対象のスレッドが wait() メソッドを呼び出しているときだけその対象スレッドに割り込む、と定義されています。

Solaris プラットフォームでは、対象のスレッドが入出力の呼び出しを行なっている時にも割り込むように、このメソッドの動作が拡張されていますが、interrupt() メソッドのこの動作に依存しないようにしてください。この拡張された動作は将来サポートされなくなる可能性があり、また異なる JVM 間でコードの互換性がなくなるためです。

スレッドの優先順位

ネイティブスレッド化された JVM での Java スレッドでは、スレッドに優先順位を付けることができますが、スケジューラはこの値を単なるヒントとして扱います。特に、演算処理が中心のスレッドがある場合には、スレッドがその優先順位どおりに実行されない可能性があります。通常、1 つのプロセスについて利用できる複数のプロセッサは動的で予測できないため、スレッドに優先順位を付けることによって、マルチタスクのマルチプロセッサシステム上での処理をスケジューリングしようとしても、あまりうまくいきません。