13

なぜRuntime.addShutdownHookを使わなければならないのか理解できません。jvm の終了時に何らかのクリーンアップを実行したい場合は、デーモン クラスの finalize メソッドをオーバーロードしてみませんか。finalize メソッドよりもシャットダウン フックを使用する利点は何ですか。

また、非推奨の関数 runFinalizersOnExit もあります。false に設定すると、ファイナライザーは実行されないと思います。これは、ファイナライザーが常にガベージ コレクションの前に実行されるという Java の保証と矛盾します。

4

2 に答える 2

23

ファイナライザーが実行されるという保証はありませfinalize()オブジェクトがガベージ コレクションされるときに呼び出されます。ただし、ガベージ コレクターは、プログラムの実行時に何も収集しない場合があります。

対照的に、シャットダウン フックは、jvm が正常に終了したときに実行されます。それでも100%保証はできませんが、かなり近いです。シャットダウン フックが実行されない特殊なケースはごくわずかです。

編集 シャットダウンフックが実行されないエッジケースを調べました

シャットダウンフックが実行されます:

  • すべての JVM スレッドの実行が完了したとき
  • System.exit() の呼び出しのため
  • ユーザーが CTRL-C を押したため
  • システム レベルのシャットダウンまたはユーザー ログオフ

シャットダウンフックは実行されません:

  • ネイティブ コードのエラーが原因で VM がクラッシュした場合、フックが実行されるかどうかは保証されません。
  • Linux の -kill コマンドまたは Windows の Terminate Process を使用して JVM を強制終了すると、JVM は即座に終了します。
于 2013-12-29T19:40:53.850 に答える
5

お問い合わせについて

jvm の終了時に何らかのクリーンアップを行いたい場合は、デーモン クラスの finalize メソッドをオーバーロードしてみませんか?

この記事から良い情報を見つけました

  1. finalize()ガベージ コレクターがオブジェクトを再利用する前に呼び出されます。JVM は、このメソッドがいつ呼び出されるかを保証しません。

  2. finalize()オブジェクトが finalize メソッドから復活した場合、GC スレッドによって 1 回だけ呼び出され、finalize が再度呼び出されることはありません。

  3. アプリケーションには、ガベージ コレクションが呼び出されないライブ オブジェクトがいくつかある場合があります。

  4. finalize メソッドによってスローされた例外は、GC スレッドによって無視されます

  5. System.runFinalization(true)およびRuntime.getRuntime().runFinalization(true)メソッドは、メソッドを呼び出す可能性を高めますが、finalize()これら 2 つのメソッドは非推奨になりました。これらのメソッドは、スレッドの安全性が欠如し、デッドロックが発生する可能性があるため、非常に危険です。

オラクルのドキュメントに従って、shutdownHooksに戻ります

public void addShutdownHook(Thread hook) 新しい仮想マシンのシャットダウン フックを登録します。

Java 仮想マシンは、次の 2 種類のイベントに応答してシャットダウンします。

  1. 最後の非デーモン スレッドが終了するか、exit (同等の System.exit) メソッドが呼び出されると、プログラムは正常に終了します。
  2. 仮想マシンは、^C の入力などのユーザー割り込み、またはユーザー ログオフやシステム シャットダウンなどのシステム全体のイベントに応答して終了します。
  3. 仮想マシンがシャットダウン シーケンスを開始すると、登録されているすべてのシャットダウン フックが不特定の順序で開始され、同時に実行されます。finalization-on-exit が有効になっている場合、すべてのフックが終了すると、呼び出されていないすべてのファイナライザーが実行されます。
  4. 最後に、仮想マシンが停止します。exit メソッドの呼び出しによってシャットダウンが開始された場合、非デーモン スレッドと同様に、デーモン スレッドはシャットダウン シーケンス中も実行し続けることに注意してください。

しかし、オラクルのドキュメントでさえそれを引用しています

シャットダウン フックもすばやく作業を終了する必要があります。プログラムが exit を呼び出すと、仮想マシンがすぐにシャットダウンして終了することが期待されます。

まれに、仮想マシンが異常終了する場合があります。つまり、正常にシャットダウンせずに実行を停止する場合があります。

これら両方のアプローチの欠点を考慮すると、以下のアプローチに従う必要があります

  1. アプリケーションの重要なリソースに依存しfinalize()たりshutdown hooks、解放したりしないでください。

  2. ブロックを適切に使用try{} catch{} finally{}し、重要なリソースを finally(}ブロックで解放します。finally{}ブロック、キャッチ、ExceptionおよびThrowable.

于 2015-12-26T14:29:01.293 に答える