torutkのブログ

ソフトウェア・エンジニアのブログ

Threadクラスのyield()メソッドの実装は?

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固有の実装になるので、LinuxSolarisWindowsで別な処理となります。それぞれ以下のファイルに実装が記述されています。

  • hotspot/src/os/linux/vm/os_linux.cpp
  • hotspot/src/os/solarisl/vm/os_solaris.cpp
  • hotspot/src/os/win32/vm/os_win32.cpp

結論を簡潔にまとめると、

細部を追ってみると、os::dont_yield()の評価は

  • Linuxでは、DontYieldALotの値であり、デフォルトではfalse
  • Solarisでは、DontYieldALotの値および、システムコールgethrtimeの結果が10ms以内かどうかであり、DontYieldALotのデフォルト値はtrue
  • Windowsでは、DontYieldALotの値であり、デフォルトではfalse

DontYieldALotの指定は、-XX:+DontYieldALot のようにコマンドラインオプションで制御します。
同様に、ConvertYieldToSleepの指定は、-XX:+ConvertYieldToSleepのようにコマンドラインオプションで制御します。