マシンをビジー状態に保つためにダミーとして使用した非常に単純なforループは、JVMのすべてのプロセスをブロックしました。ストールは、最も単純なコンステレーションでも持続しました。
2つのforループ(最初のブロッキング、2番目のブロッキングではない)の例を次に示します。唯一の違いは、イテレータ「i」のタイプ、つまりintとlongです。
public class Main {
public static void main(String[] args) {
Timer timer = new Timer();
timer.schedule(new MyTimerHandler(), new Date(), 1000);
float b = 1;
// after a few seconds this loop uses 200% CPU and blocks the timer
for (int i=0; i<2000000000; i++) {
b += i/3.141592;
}
System.out.println("Result: " + b);
b = 1;
// this version uses 100% CPU throughout the entire loop and doesn't block the timer
for (long i=0; i<2000000000L; i++) {
b += i/3.141592;
}
System.out.println("Result: " + b);
timer.cancel();
}
}
// helps to show whether the JVM is stalled or not
class MyTimerHandler extends TimerTask {
@Override
public void run() {
System.out.println("timestamp=" + new Date().toString());
}
}
2つの異なるマシン/jvmで問題を再現しました。
- Arch Linux 3.7.7-1-ARCH ... x86_64 GNU / Linuxjavaバージョン"1.7.0_09"、Java(TM)SEランタイム環境(ビルド1.7.0_09-b05)
- OSX 10.8.2 ... x86_64javaバージョン"1.7.0_07"、Java(TM)SEランタイム環境(ビルド1.7.0_07-b10)
更新と明確化:
- 問題は、与えられた例を「解決」するのではなく、なぜ、何が正確に起こっているのかということです。つまり、最初のforループが2倍以上のCPUを使用し、JVMのすべてのスレッドをブロックするという奇妙な動作をするのはなぜですか。
- サンプルコードは終了し、正しい結果が得られます。
- タイマーはデモンストレーション用であり、問題はタイマーの有無にかかわらず発生します。
- intの制限は2,000,000,000をはるかに超えています。
- この問題は、これまでにテストされたすべてのJVMに影響します。
- JProfilerおよびその他のデバッグツールは、最初のforループでも中断/停止します。