web-dev-qa-db-ja.com

finallyブロックは常に実行されますか?

最終的にJavaで実行されない可能性のある条件はありますか?ありがとう。

110
Warrior

Sun Tutorials から

注:tryまたはcatchコードの実行中にJVMが終了すると、finallyブロックが実行されない場合があります。同様に、tryまたはcatchコードを実行しているスレッドが中断または強制終了された場合、アプリケーション全体が継続しても、finallyブロックは実行されない場合があります。

Finallyブロックが実行されない他の方法は知りません...

136
hhafez

System.exit は、仮想マシンをシャットダウンします。

現在実行中のJava仮想マシン。引数はステータスコードとして機能します。慣例により、ゼロ以外のステータスコードは異常終了を示します。

このメソッドは、クラスexitRuntimeメソッドを呼び出します。このメソッドは通常戻りません。

    try {
        System.out.println("hello");
        System.exit(0);
    }
    finally {
        System.out.println("bye");
    } // try-finally

「bye」は上記のコードでは出力されません。

62
Eugene Yokota

他の人が言ったことを拡張するために、JVMの終了などを引き起こさないものはすべて、最終的にブロックされます。したがって、次の方法:

public static int Stupid() {
  try {
    return 0;
  }
  finally {
    return 1;
  }
}

奇妙なことに、コンパイルと1の両方が返されます。

49
Daniel Nadasi

System.exitに関連して、finallyブロックが実行されない特定のタイプの壊滅的な障害もあります。 JVMのメモリが完全になくなると、キャッチまたは最終的に発生せずにJVMが終了する場合があります。

具体的には、愚かにも使用しようとしたプロジェクトを覚えています

catch (OutOfMemoryError oome) {
    // do stuff
}

JVMにcatchブロックを実行するためのメモリが残っていないため、これは機能しませんでした。

15
Zarkonnen
try { for (;;); } finally { System.err.println("?"); }

その場合、finallyは実行されません(非推奨のThread.stopが呼び出されるか、同等のものが、たとえばツールインターフェースを介して呼び出されます)。

10

このスレッドでは、Sunのチュートリアルが誤って引用されています。

注:tryまたはcatchコードの実行中にJVMが終了すると、finallyブロックwill実行されません。同様に、tryコードまたはcatchコードを実行しているスレッドが中断または強制終了された場合、アプリケーション全体が継続しても、finallyブロックwillは実行されません。

最終的にブロックするためにSunのチュートリアルをよく見ると、「実行しない」とは言わず、「実行しない可能性がある」と正しい説明があります。

注:tryまたはcatchコードの実行中にJVMが終了した場合、finallyブロックmay実行されません。同様に、tryコードまたはcatchコードを実行しているスレッドが中断または強制終了された場合、アプリケーション全体が継続していても、finallyブロックmayは実行されません。

この動作の明らかな理由は、system.exit()の呼び出しがランタイムシステムスレッドで処理されるため、jvmのシャットダウンに時間がかかり、スレッドスケジューラが最終的に実行を要求できるためです。最終的には常に実行されるように設計されていますが、jvmをシャットダウンしている場合、最終的に実行される前にjvmがシャットダウンすることがあります。

8
saurabh

また、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

そして「最終的に」印刷されることはありません

6
wheleph

Finallyブロックをバイパスできる条件を次に示します。

  1. tryまたはcatchコードの実行中にJVMが終了した場合、finallyブロックは実行されない可能性があります。
  2. 通常のシャットダウン-これは、最後の非デーモンスレッドが終了するときに発生しますOR Runtime.exit() の場合
  3. スレッドが終了すると、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
5

最終的にブロックコードの実行をブロックする2つの方法があります。
1。 System.exit()を使用します。
2。どういうわけか実行制御がブロックしようとして到達しない場合。
見る:

public class Main
{
  public static void main (String[]args)
  {
    if(true){
        System.out.println("will exceute");
    }else{
        try{
            System.out.println("result = "+5/0);
        }catch(ArithmeticException e){
          System.out.println("will not exceute");
        }finally{
          System.out.println("will not exceute");  
        }
    }
  }
}
1
Aagam Jain

次の場合、finallyブロックは実行されません:-

  • System.exit(0)tryブロックから呼び出されたとき。
  • JVMがメモリ不足になったとき
  • Javaプロセスがタスクマネージャーまたはコンソールから強制的に強制終了される場合
  • tryブロックのデッドロック状態
  • 電源障害によりマシンがシャットダウンしたとき

最終的にブロックが実行されない他のフリンジケースもあります。

プレイフレームワークに関連して、finallyブロックが実行されないという非常に特殊なケースに遭遇しました。

このコントローラーアクションコードのfinallyブロックは例外の後にのみ呼び出され、呼び出しが実際に成功したときは呼び出されなかったことに驚いた。

try {
    InputStream is = getInputStreamMethod();
    renderBinary(is, "out.Zip");
catch (Exception e) {
    e.printStackTrace();
} finally {
    cleanUp();
}

RenderBinary()が呼び出されたときに、おそらくスレッドが終了するか何かです。他のrender()呼び出しでも同じことが起こると思いますが、確認しませんでした。

Try/catchの後にrenderBinary()を移動することで問題を解決しました。さらに調査した結果、playは@Finallyアノテーションを提供し、コントローラーアクションの実行後に実行されるメソッドを作成することが明らかになりました。ここでの注意点は、コントローラーで任意のアクションが実行された後に呼び出されるということです。そのため、常に良い選択とは限りません。

0
Jeremy Goodell