finally {}块不会执行的情况是什么?

时间:2012-09-14 19:15:34

标签: java jvm try-catch try-catch-finally

在Java try{} ... catch{} ... finally{}块中,finally{}中的代码通常被认为是“保证”运行,无论try / catch中发生什么。但是,我知道至少有两种情况,执行:

  • 如果调用System.exit(0);或者,
  • 如果异常被抛出到JVM并且发生默认行为(即printStackTrace()并退出)

是否有任何其他程序行为会阻止finally{}块中的代码执行?代码在什么具体条件下执行?

编辑:由于NullUserException指出,第二种情况实际上并非如此。我认为这是因为标准错误中的文本在标准输出之后打印出来,防止文本在没有向上滚动的情况下被看到。道歉。

9 个答案:

答案 0 :(得分:33)

如果您致电System.exit(),程序会立即退出而不会调用finally

JVM崩溃,例如分段错误,也会阻止最终被调用。即JVM此时立即停止并生成崩溃报告。

无限循环也会阻止最终被调用。

抛出Throwable时始终会调用finally块。即使你调用Thread.stop()来触发在目标线程中抛出ThreadDeath。这可以被捕获(它是Error)并且将调用finally块。


public static void main(String[] args) {
    testOutOfMemoryError();
    testThreadInterrupted();
    testThreadStop();
    testStackOverflow();
}

private static void testThreadStop() {
    try {
        try {
            final Thread thread = Thread.currentThread();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    thread.stop();
                }
            }).start();
            while(true)
                Thread.sleep(1000);
        } finally {
            System.out.print("finally called after ");
        }
    } catch (Throwable t) {
        System.out.println(t);
    }
}

private static void testThreadInterrupted() {
    try {
        try {
            final Thread thread = Thread.currentThread();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    thread.interrupt();
                }
            }).start();
            while(true)
                Thread.sleep(1000);
        } finally {
            System.out.print("finally called after ");
        }
    } catch (Throwable t) {
        System.out.println(t);
    }
}

private static void testOutOfMemoryError() {
    try {
        try {
            List<byte[]> bytes = new ArrayList<byte[]>();
            while(true)
                bytes.add(new byte[8*1024*1024]);
        } finally {
            System.out.print("finally called after ");
        }
    } catch (Throwable t) {
        System.out.println(t);
    }
}

private static void testStackOverflow() {
    try {
        try {
            testStackOverflow0();
        } finally {
            System.out.print("finally called after ");
        }
    } catch (Throwable t) {
        System.out.println(t);
    }
}

private static void testStackOverflow0() {
    testStackOverflow0();
}

打印

finally called after java.lang.OutOfMemoryError: Java heap space
finally called after java.lang.InterruptedException: sleep interrupted
finally called after java.lang.ThreadDeath
finally called after java.lang.StackOverflowError

注意:在每种情况下,线程都保持运行,即使在SO,OOME,Interrupted和Thread.stop()之后!

答案 1 :(得分:9)

try块中的无限循环。

损坏内存?程序不再按书面运行?我实际上已经在DOS机器上调试了一次。

答案 2 :(得分:1)

当最终自身抛出异常(或导致错误)时,有可能部分执行

答案 3 :(得分:1)

一个可能是“最终是守护程序线程的一部分,它可能无法执行”。

答案 4 :(得分:1)

最终不会被召唤的唯一时间是:

如果电源关闭

  1. 如果您调用System.exit()
  2. 如果JVM首先崩溃
  3. 如果try块中存在无限循环
  4. 如果电源关闭

答案 5 :(得分:1)

在try块中的不同语句中测试 finally 块。

 public static void main(String [] args){

    try{
        System.out.println("Before Statement");
        /*** Statement ***/
        System.out.println("After Statement");
    }
    catch(Exception e){
    }
    finally{
        System.out.println("Finally is Executed");
    }

finally块执行的语句如下:

  1. Thread.currentThread().interrupted();
  2. Thread.currentThread().destroy();
  3. Thread.currentThread().stop();
  4. Thread.sleep(10);
  5. Thread.currentThread().interrupt();
  6. Runtime.getRuntime().addShutdownHook(Thread.currentThread());
  7. 如果发生任何异常。
  8. 如果没有例外。
  9. finally块未执行的语句如下:

    1. Thread.currentThread().suspend();
    2. System.exit(0);
    3. JVM崩溃。
    4. CPU芯片的电源关闭。
    5. 操作系统杀死了JVM进程。
    6. Runtime.getRuntime().exit(0);
    7. Runtime.getRuntime().halt(0);

答案 6 :(得分:0)

我认为当JVM由于任何原因突然退出时,这可能是因为控件不会进入finally块而永远不会执行。

答案 7 :(得分:0)

您可以将其作为守护程序线程的一部分。您可以使用方法setDaemon(boolean status),该方法用于将当前线程标记为守护程序线程或用户线程,并在需要时退出JVM。这将使您能够在finally{}执行之前退出JVM。

答案 8 :(得分:0)

finally块永远不会执行的另一个可能的实例是由于在输入try块之前返回的方法的设计,就像我不时看到的一些非常糟糕的代码的情况一样:

public ObjectOfSomeType getMeAnObjectOfSomeType() throws SomeHorrendousException {
    if (checkSomeObjectState()) {
        return new ObjectOfSomeType();
    }

    try {
        // yada yada yada...
    } catch (SomeHorrendousException shexc) {
        // wow, do something about this horrendous exception...
    } finally {
        // do some really important cleanup and state invalidation stuff...
    }

我知道你们没有人会这样做,所以我犹豫是否愿意将此作为一种可能的情况添加,但是,呃,这是星期五,这是什么意思; )