かずきのBlogの[Java]知らなかったよ こんな機能より。
JavaのVMが終了する条件
コンソールでのCtrl+CやWindowsのタスクマネージャからの強制終了といった外的要因以外でJavaのVMが終了するには
- デーモンスレッドではないスレッドが全て終了する
- System.exit()を呼び出す
のふたつの方法があります。
デーモンスレッドというのはThreadクラスの setDaemon でフラグを立てて実行したスレッドのことです。
このデーモンスレッドの機能は、タイマーによる定時処理や、通信待ちうけのスレッドで使われることがあります。(サーバにおけるメインの通信待ちうけはデーモンだと困るので管理用の副次的な通信待ちうけなどに限られます)
System.exit() はJavaのVMを終了させるメソッドです。
なお、swingのJFrameで setDefaultCloseOperation()に EXIT_ON_CLOSE を設定した場合などは内部でSystem.exit()が呼び出されます。
finally節が実行されない
System.exit()はVM自体を終了させるため、以下のようなコードでfinally節が実行されません。
try {
// exitでVMを終了させる
System.exit(0);
} finally {
System.out.println("finally節だが実行されない");
}
これと同様に、デーモンスレッド中でのfinallyも必ず呼ばれるとは限りません。 try節の実行中に非デーモンスレッドが全て終了した場合、デーモンスレッド上でfinallyに到達する前に VMが終了してしまうことがあります。
となると、デーモンスレッドでリソースの解放を行いたい場合はどうすればよいのでしょうか?
シャットダウンフック
JavaのVMにはシャットダウンフックと呼ばれる機能があります。 「シャットダウンフック API の設計」というQ&Aがありますので参考にして見てください。
シャットダウンフックを使うにはjava.lang.Runtimeクラスの addShutdownHook()を用います。
引数にThreadのインスタンスを渡すのですが、このThreadは「初期化されただけで起動していないスレッド」である必要があります。詳細はjavadocに記述されている通りですが、
「シャットダウンフック」は初期化されただけで起動していないスレッドです。
仮想マシンがシャットダウンシーケンスを開始すると、すべての登録済みシャットダウンフックを、指定されていない順序で起動し並行して実行します。
フックがすべて終了すると、終了時のファイナライズが有効である場合はすべての呼び出されていないファイナライザを実行します。
最後に、仮想マシンは停止します。
exit を呼び出してシャットダウンが開始された場合は、デーモンではないスレッドと同様、デーモンスレッドはシャットダウンシーケンスの間、実行を続けます。
といった動きをします。これを利用してデーモンスレッドのリソース解放などを行うことができます。
また、このシャットダウンフックを利用することでjava.io.Fileの deleteOnExit 機能(VM終了時に削除される一時ファイル)のようなことをすることもできます。もっとも、deleteOnExitは1.2からの機能で1.3から導入されたシャットダウンフックとは別の方法でフックしているようです。
投稿日時 : 2007年11月26日 14:28