最終的にJavaで実行されない可能性がある条件はありますか? ありがとう。
12 に答える
Sunのチュートリアルから
注: try または catch コードの実行中に JVM が終了すると、finally ブロックが実行されない場合があります。同様に、try または catch コードを実行しているスレッドが中断または強制終了された場合、アプリケーション全体が続行されても、finally ブロックが実行されない可能性があります。
finally ブロックが実行されない他の方法については知りません...
System.exitは仮想マシンをシャットダウンします。
現在実行中の Java 仮想マシンを終了します。引数はステータス コードとして機能します。慣例により、ゼロ以外のステータス コードは異常終了を示します。
このメソッドは
exit
classのメソッドを呼び出しますRuntime
。このメソッドが正常に戻ることはありません。
try {
System.out.println("hello");
System.exit(0);
}
finally {
System.out.println("bye");
} // try-finally
上記のコードでは「さようなら」は出力されません。
他の人が言ったことを拡張するだけで、JVM の終了などを引き起こさないものはすべて、finally ブロックが発生します。したがって、次の方法:
public static int Stupid() {
try {
return 0;
}
finally {
return 1;
}
}
不思議なことに、コンパイルして 1 を返します。
このスレッドでは、Sunチュートリアルが誤って引用されています。
注:tryまたはcatchコードの実行中にJVMが終了すると、finallyブロックは実行されません。同様に、tryまたはcatchコードを実行しているスレッドが中断または強制終了された場合、アプリケーション全体が続行されても、finallyブロックは実行されません。
太陽のチュートリアルでfinallyブロックを詳しく調べると、「実行されない」とは表示されませんが、「実行されない可能性があります」と表示されます。正しい説明は次のとおりです。
注:tryまたはcatchコードの実行中にJVMが終了すると、finallyブロックが実行されない場合があります。同様に、tryまたはcatchコードを実行しているスレッドが中断または強制終了された場合、アプリケーション全体が継続していても、finallyブロックが実行されない可能性があります。
この動作の明らかな理由は、system.exit()の呼び出しがランタイムシステムスレッドで処理されるため、jvmのシャットダウンに時間がかかる場合があります。その間、スレッドスケジューラは最終的に実行を要求できます。したがって、finallyは常に実行されるように設計されていますが、jvmをシャットダウンしている場合、最終的に実行される前にjvmがシャットダウンすることがあります。
try { for (;;); } finally { System.err.println("?"); }
その場合、finally は実行されません (deprecatedThread.stop
が呼び出された場合、またはツール インターフェイスを介して同等のものが呼び出された場合を除きます)。
try
また、ブロック内でデッドロック/ライブロックが発生した場合。
これを示すコードは次のとおりです。
public class DeadLocker {
private static class SampleRunnable implements Runnable {
private String threadId;
private Object lock1;
private Object lock2;
public SampleRunnable(String threadId, Object lock1, Object lock2) {
super();
this.threadId = threadId;
this.lock1 = lock1;
this.lock2 = lock2;
}
@Override
public void run() {
try {
synchronized (lock1) {
System.out.println(threadId + " inside lock1");
Thread.sleep(1000);
synchronized (lock2) {
System.out.println(threadId + " inside lock2");
}
}
} catch (Exception e) {
} finally {
System.out.println("finally");
}
}
}
public static void main(String[] args) throws Exception {
Object ob1 = new Object();
Object ob2 = new Object();
Thread t1 = new Thread(new SampleRunnable("t1", ob1, ob2));
Thread t2 = new Thread(new SampleRunnable("t2", ob2, ob1));
t1.start();
t2.start();
}
}
このコードは、次の出力を生成します。
t1 inside lock1
t2 inside lock1
そして「最終的に」印刷されることはありません
try または catch コードの実行中に JVM が終了すると、finally ブロックが実行されない場合があります。(ソース)
通常のシャットダウン - これは、デーモン以外の最後のスレッドが終了したとき、または Runtime.exit() ( source ) のときに発生します。
スレッドが終了すると、JVM は実行中のスレッドのインベントリを実行し、残っているスレッドがデーモン スレッドだけの場合は、正常なシャットダウンを開始します。JVM が停止すると、残りのデーモン スレッドはすべて放棄され、最終的にブロックは実行されず、スタックは巻き戻されず、JVM はただ終了します。デーモン スレッドは慎重に使用する必要があります。クリーンアップなしでいつでも安全に放棄できる処理アクティビティはほとんどありません。特に、何らかの種類の I/O を実行する可能性のあるタスクにデーモン スレッドを使用するのは危険です。デーモン スレッドは、メモリ内キャッシュから期限切れのエントリを定期的に削除するバックグラウンド スレッドなどの「ハウスキーピング」タスク用に保存するのが最適です。(ソース)
最後の非デーモン スレッドの終了例:
public class TestDaemon {
private static Runnable runnable = new Runnable() {
@Override
public void run() {
try {
while (true) {
System.out.println("Is alive");
Thread.sleep(10);
// throw new RuntimeException();
}
} catch (Throwable t) {
t.printStackTrace();
} finally {
System.out.println("This will never be executed.");
}
}
};
public static void main(String[] args) throws InterruptedException {
Thread daemon = new Thread(runnable);
daemon.setDaemon(true);
daemon.start();
Thread.sleep(100);
// daemon.stop();
System.out.println("Last non-daemon thread exits.");
}
}
出力:
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Last non-daemon thread exits.
Is alive
Is alive
Is alive
Is alive
Is alive
特に play フレームワークに関連して、finally ブロックが実行されないという非常に特殊なケースに遭遇しました。
このコントローラー アクション コードの finally ブロックは例外の後でのみ呼び出され、呼び出しが実際に成功したときは呼び出されないことに驚きました。
try {
InputStream is = getInputStreamMethod();
renderBinary(is, "out.zip");
catch (Exception e) {
e.printStackTrace();
} finally {
cleanUp();
}
おそらく、renderBinary() が呼び出されたときにスレッドが終了するか、何かが発生します。他の render() 呼び出しでも同じことが起こるのではないかと思いますが、確認していません。
renderBinary() を try/catch の後に移動することで問題を解決しました。さらに調査した結果、play は @Finally アノテーションを提供して、コントローラー アクションの実行後に実行されるメソッドを作成することが明らかになりました。ここでの注意点は、これはコントローラーでの任意のアクションの実行後に呼び出されるため、常に適切な選択であるとは限らないことです。