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