ライセンス数が有限のライセンス サーバーからライセンス オブジェクトを取得/解放する方法を持つ、ライセンス付き API を使用しています。アプリケーションの開始時にライセンスを取得するメソッドを呼び出しますが、プログラムが突然終了またはクラッシュした場合 (例外、SIGTERM など) にライセンスが解放されるようにしたいと考えています。シャットダウン フックは、この問題に対処するための最良の方法ですか?
4 に答える
@thedanは、ハードJVMのクラッシュについて正しいです。JVMが激しくクラッシュしたり、SIGKILLを取得したりした場合、JVMは終了する前に何も実行する機会がありません。そのシナリオでは、Javaでこれを修正するためにできることは何もありません。(しかし、状況は他の言語でも同じです...)
ただし、DVM以外のすべてのスレッドが終了し、System.exit()を呼び出し、SIGINTを取得するなどの応答として、JVMが正常にシャットダウンする場合、JVMはシャットダウンフックを実行しようとします。Q&Aページとjavadocsに、Javaのシャットダウンフックメカニズムに関する詳細情報があります。
このfinally
アプローチもオプションですが、JVMが終了する前に問題のスレッドが終了した場合にのみ機能します。System.exit()
が呼び出された場合、またはJVMがシグナルによって終了した場合、これは発生しません。シャットダウンフックは、より多くの状況で機能します。
(私の考えでfinally
は、アプリケーション全体ではなく、単一のスレッドでクリーンを実行するためのものです。ただし、アプリケーションが1つのスレッドのみで構成されている場合、または正常なシャットダウンを担当するマスタースレッドがある場合は、...finally
アプリケーションのクリーンアップの目的を果たすことができます。)
実際の解決策は、ライセンスを使用しているアプリケーションインスタンスが解放されずになくなることをライセンスマネージャーが検出できるように、ライセンスされたAPIを構成することです。これが可能かどうかは、ライセンスマネージャーによって異なります。
プログラムが JVM のクラッシュによって終了した場合、呼び出されているものに依存することはできません。
JVM に関係のない例外によってプログラムが終了した場合は、すべてを try/catch/finally ブロックでラップできるはずです。finally ブロック内のすべてのコードは、コードが終了する前に実行されることが保証されます。
main
例外として、の本文をでラップできますtry/catch/block
。SIGTERM
信号を処理するために、シャットダウンフックを追加できます。ただし、シャットダウンフックがのような信号に対してトリガーされることは保証されていませんSIGKILL
。
Java docから:
まれに、仮想マシンが異常終了する場合があります。つまり、正常にシャットダウンせずに実行を停止する場合があります。これは、仮想マシンが外部で終了した場合に発生します。たとえば、
SIGKILL
UnixのシグナルやTerminateProcess
MicrosoftWindowsの呼び出しなどです。また、内部データ構造が破損したり、存在しないメモリにアクセスしようとしたりして、ネイティブメソッドが失敗した場合にも、仮想マシンが異常終了する可能性があります。仮想マシンが異常終了した場合、シャットダウンフックが実行されるかどうかについて保証することはできません。
これは、Sytem.exit()を呼び出さないことで実現できます。main()で、「最後の防衛線」を作成します。
try {
startApp();
} catch (Exception ex) {
// do some logging
} finally {
releaseLicense();
}