JIT コンパイラの Thread#stop() 対応

first-published: Sep 22 23:45, 2001

last-modified: July 2 13:00, 2002


Java Just-in-Time (JIT)コンパイラ、 Ahead-of-Time (AOT) コンパイラが Thread#stop() メソッドへを意識して扱わねばならないことを述べます。

Thread#stop() メソッド

java.lang.Thread クラスの stop() メソッドを使うと、実行 中の他のスレッドを強制的に止めることができます。正確に言 うと、stop() されたスレッドは java.lang.ThreadDeath 例外 が throw された状態になり、通常のプログラムは ThreadDeath を catch しないので、そのスレッドは終了しま す。他の多くの例外とは違って、ThreadDeath は非同期例外 (Java 言語仕様 第 2版 11.3.2) という種類の例外です。他の多くの例外は同期例外と いって、メソッド呼び出し等、何かをしようとしたスレッドに 対して throw されます。それに対して、非同期例外はスレッ ド自身が何かしたわけでもなく、throw された状態になり得ます。

メソッド呼び出しを含まないループを長時間実行している Java スレッドがあったとしましょう。他のスレッドから stop() された場合、ループから抜けなければなりません。と ころが、JIT コンパイラ、AOT コンパイラといった Java 処理 系が非同期例外を考慮していない場合、ループ実行中のスレッ ドは stop() されたことに気付けません。ここでそのループが 無限ループだった場合、本来は stop() されたことでループか ら抜けるところ、抜けずに永久にルー プを続けることになってしまいます。

Kaffe 1.0.6に含まれる test/regression/ThreadStop.java が、Java 処理系の Thread#stop() への対応具合を調べる格好 のテストプログラムとなっています。対応できている場合、 「All tests completed」と表示された後プログラムは終了す るのですが、対応できていない場合、表示後、プログラムはい つまでも終了しません。あるスレッドが stop() されたにも関 わらず止まらないので、処理系自体も終了しないのです。

通常、JIT, AOT コンパイラは「メソッド呼び出しから戻った 際に例外が throw されているかどうかチェックする」という コードを生成します。なので、ループの中にメソッド呼び出し がひとつでもあれば、ThreadDeath 例外、つまり stop() され たことを検出できます。しかしメソッド呼び出しがない場合、 例外チェックが行われない恐れがあります。無限ループの実行 中であっても、確実に stop() されたことに気付かせなければ なりません。

stop() 対応の方法

shuJIT は ポーリングで例外チェックを行いま す。ループの最中に最低でも一度は例外チェックを行うように、 後方ジャンプの直前に例外チェックコードを生成します。ただ、 ループ中にメソッド呼び出しがある場合はあらためて例外チェッ クコードを生成する必要はないため、省きます。

スレッドが自発的にポーリングするとどうしても性能は低下し ます。ポーリングといった同期的な (synchronous) 方法では なく、外からスレッドのコンテクストを操作する、シグナルを 利用する、といった非同期な (asynchronous) 方法も考えられ ます。

各種 JIT コンパイラの対応

上述のテストコード ThreadStop.java を用いて、Linux 用の 各種 JIT コンパイラを試験しました。次の JIT は Thread#stop() にきちんと対応していないようです。
ただ、Thread#stop() で無限ループが止まらなくとも 現実に困る局面はまずありませんし、 ポーリングはある程度のオーバヘッドを導入し、 性能が低下してしまいます。Thread#stop() は deprecated メソッドですし、 対応しないという選択もアリだと思います。

Back to