在什么情况下 finally {} 块不会执行?

2022-01-16 00:00:00 jvm try-catch java try-catch-finally

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

In a Java try{} ... catch{} ... finally{} block, code within the finally{} is generally considered "guaranteed" to run regardless of what occurs in the try/catch. However, I know of at least two circumstances under which it will not execute:

  • 如果 System.exit(0) 被调用;或者,
  • 如果异常一直抛出到 JVM 并且发生默认行为(即,printStackTrace() 并退出)
  • If System.exit(0) is called; or,
  • if an Exception is thrown all the way up to the JVM and the default behavior occurs (i.e., printStackTrace() and exit)

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

Are there any other program behaviors that will prevent the code in a finally{} block from executing? Under what specific conditions will the code execute or not?

正如 NullUserException 所指出的,第二种情况实际上是不正确的.我认为这是因为标准错误中的文本在标准输出之后打印,防止在不向上滚动的情况下看到文本.:) 抱歉.

As NullUserException pointed out, the second case is actually not true. I thought it was because the text in standard error printed after that in standard out, preventing the text from being seen without scrolling up. :) Apologies.

推荐答案

如果调用System.exit() 程序立即退出而不调用 finally.

JVM 崩溃,例如Segmentation Fault,也会阻止 finally 被调用.即 JVM 在此时立即停止并生成崩溃报告.

A JVM Crash e.g. Segmentation Fault, will also prevent finally being called. i.e. the JVM stops immediately at this point and produces a crash report.

无限循环也会阻止 finally 被调用.

An infinite loop would also prevent a finally being called.

finally 块总是在抛出 Throwable 时调用.即使您调用 Thread.stop() 触发 ThreadDeath 在目标线程中被抛出.这可以被捕获(这是一个 Error) 并且 finally 块将被调用.

The finally block is always called when a Throwable is thrown. Even if you call Thread.stop() which triggers a ThreadDeath to be thrown in the target thread. This can be caught (it's an Error) and the finally block will be called.

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() 之后也是如此!

Note: in each case the thread kept running, even after SO, OOME, Interrupted and Thread.stop()!

相关文章