Java読書会BOFの宿題事項です。
おっと、いきなりnativeメソッドです。
public static native void yield();
ここから先は、JDKのソースを持っていないと追えません。JDK 6 (Mustang) b96でこの先を追いかけてみます。
まず、java.lang.Threadクラスに対応するネイティブコードが記述されているj2se/src/share/native/java/lang/Thread.c を見ます。
static JNINativeMethod methods[] = { [中略] {"yield", "()V", (void *)&JVM_Yield}, [中略] };
というコードがあります。関数ポインタが登録されているので、JVM_Yieldの実体が定義されているソースファイルを探すことにします。最近のJDKのネイティブメソッドはとても追うのが大変です。JVMがつく関数は、JavaVM関連ソースに記述されるので、HotSpotのディレクトリの中を探します。hotspot/src/share/vm/prims/jvm.cpp を見ます。
JVM_ENTRY(void, JVM_Yield(JNIEnv *env, jclass threadClass)) JVMWrapper("JVM_Yield"); if (os::dont_yield()) return; // When ConvertYieldToSleep is off (default), this matches the classic VM use of yield. // Critical for similar threading behaviour if (ConvertYieldToSleep) { os::sleep(thread, MinSleepInterval, false); } else { os::yield(); } JVM_END
os::はOS固有の実装になるので、Linux、Solaris、Windowsで別な処理となります。それぞれ以下のファイルに実装が記述されています。
- hotspot/src/os/linux/vm/os_linux.cpp
- hotspot/src/os/solarisl/vm/os_solaris.cpp
- hotspot/src/os/win32/vm/os_win32.cpp
結論を簡潔にまとめると、
- Linuxでは、POSIX.1bのsched_yield()を呼び出します。
- Solarisでは、Solaris OSのシステムコール thr_yield()を呼び出します。
- Windowsでは、Win32 APIのSwitchToThreadを呼び出します
細部を追ってみると、os::dont_yield()の評価は
- Linuxでは、DontYieldALotの値であり、デフォルトではfalse
- Solarisでは、DontYieldALotの値および、システムコールgethrtimeの結果が10ms以内かどうかであり、DontYieldALotのデフォルト値はtrue
- Windowsでは、DontYieldALotの値であり、デフォルトではfalse
DontYieldALotの指定は、-XX:+DontYieldALot のようにコマンドラインオプションで制御します。
同様に、ConvertYieldToSleepの指定は、-XX:+ConvertYieldToSleepのようにコマンドラインオプションで制御します。