101

ようやくJavaで実行されない可能性がある条件はありますか?ありがとう。


  • これは、ある有名な会社に就職しようとしたときに尋ねられる可能性がある質問ですか。 - Tom Hawtin - tackline
  • @ TomHawtin-tackline名前を付けて気にしますか? (神様、この記事が何歳だったのか懐かしいです。) - Hele
  • @ Hele私はゲームをあきらめたくはありませんが、あなたはそれをグーグルすることができます。 - Tom Hawtin - tackline

12 답변


127

からSunのチュートリアル

注:試行中にJVMが終了した場合   キャッチコードが実行されている   finallyブロックは実行できません。   同様に、スレッドを実行している場合   コードが中断または中断される   殺された、最終的なブロックはそうではないかもしれない   アプリケーションとしても実行   全体が続きます。

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


  • @dhiller - "電源を切る"と確信しています。 「JVMが終了した場合...」に含まれています。 :-p - Jason Coco
  • @Jason Coco:(力の喪失時などに)終了することは、終了することとまったく同じではありません。後者は多少なりとも組織化されたプロセスであり、前者に至ります。 ; P - user359996
  • スレッドが中断されても、すぐには停止されません。割り込みを検出してタスクを停止するのはスレッド内のコード次第であるため、最後にコードを実行します。 - Bart van Heukelom
  • finallyブロックで例外が発生した場合、残りのブロックは実行されません。 - Adriaan Koster
  • まあそれは吸う! - eiran

58

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

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

このメソッドはexitメソッドの   クラスRuntime。この方法はありません   正常に戻ります。

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

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


  • また、例外によってJava仮想マシンがシャットダウンされるはずです。 - kaissun
  • System.exit(0)の実行中に例外が発生した場合は、最後にblockが実行されます。 - halil

47

他の人が言ったことをさらに拡大するために、JVMの終了のような何かを引き起こさないものは、最後のブロックを招くでしょう。だから次の方法:

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

奇妙なことに、コンパイルも1も返します。


  • これは、数週間前のかなりの数時間、私を本当に混乱させました。 - nickf
  • finallyブロックから値を返すことは悪い考えと考えられています。 tryブロックからのみ戻るか、try / finallyブロックの外側から戻ってください。ほとんどのIDEはこれを警告でマークします。 - Ran Biron
  • @ nickfあなたがもう混乱していないことを私は集める。最初に0を保持する関数の戻り値を格納するメモリ(またはレジスタ)が、finallyブロックが実行されると上書きされることを推測できただけです。 。 - Yaneeve
  • C#では、finallyブロックから戻ることは許可されていません。 - JMCF125
  • @RanBironもちろんです。彼はfinallyブロック内で戻ることを実際には推奨していませんでした。彼はreturn文でもまだそのブロック内のコードを実行させることを実証しようとしていました。 - Aquarelle

14

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

具体的には、私たちが愚かに使用しようとしたプロジェクトを思い出します

catch (OutOfMemoryError oome) {
    // do stuff
}

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


  • OutOfMemoryErrorが投げられると、通常はたくさんのメモリが残ります(GCのスラッシングを止めるため)。しかし、繰り返しキャッチすると、GCスラッシングに戻ることは明らかです。 - Tom Hawtin - tackline
  • 未チェックの例外をキャッチしないでください。 - Sergii Shevchyk
  • 私はjdk7を使って私の側で試しましたが、それはOutOfMemory Errorをキャッチしました! - Jaskey

9

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

その場合、finallyは実行されません(非推奨の場合を除く)Thread.stopと呼ばれる、またはそれと同等のものです。


  • このページでは、ThreadDeathエラーがスローされ、Thread.stop()が呼び出されたときにスタックが正常にアンワインドされると主張しています。行方不明のキャッチはありますか?download.oracle.com/docs/cd/E17476_01/javase/1.5.0/docs/guide/… - spurserh
  • キャッチがあるとは思わない。おそらくそこにはない漁獲量を想像しているのでしょう。明示的にthrow、 そうしてfinallyブロックは期待どおりに実行されます。try { throw new ThreadDeath(); } finally { System.err.println("?"); } - Tom Hawtin - tackline

7

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

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

finallyブロックについてSunのチュートリアルを詳しく見てみると、「実行されません」とは表示されませんが、「実行されない場合があります」 これが正しい説明です

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

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


5

また、内部でデッドロック/ライブロックが発生した場合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ブロックは終了しないので、finallyブロックは実行の機会を得るべきではありません。無限ループについても同じことが言えます。 - Jeff Mercado

4

これがfinallyブロックを回避できるいくつかの条件です。

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


0

playフレームワークに関連したfinallyブロックが実行されないという非常に特殊なケースに出会いました。

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

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

おそらくスレッドが終了するか、renderBinary()が呼び出されたときに何かが発生しています。私は他のrender()呼び出しについても同じことが起こるのではないかと思いますが、検証はしませんでした。

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


0

以下の場合、最後にブロックは実行されません。

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

他のフリンジケースもあるかもしれません、そこでは最終的にブロックは実行されません。


0

最後にブロックコードの実行を停止する方法は2つあります。

1. System.exit()を使用してください。

どういうわけか実行制御がtryブロックに達していない場合。

見る:

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

//If ArithmeticException Occur Inner finally would not be executed
class Temp
{
    public static void main(String[] s)
    {
        try
        {
        int x = 10/s.length;
        System.out.println(x);
        try
            {
                int z[] = new int[s.length];
                z[10] = 1000;
            }catch(ArrayIndexOutOfBoundsException e)
            {
                System.out.println(e);
            }
         finally
        {
            System.out.println("Inner finally");
        }
        }
        catch(ArithmeticException e)
        {
            System.out.println(e);
        }
    finally 
    {
        System.out.println("Outer Finally"); 
    }

System.out.println("Remaining Code");   
}
}


  • インデントを改善し、いくつかの詳細を追加してください。 - ROMANIA_engineer
  • 実行は内部のtryブロックに到達することすらできません、もちろん内部は最終的に実行されないでしょう。 - Anton Arhipov

リンクされた質問


関連する質問

最近の質問