考虑到这段代码,我能绝对确定finally块总是执行的吗,不管something()是什么?

try {  
    something();  
    return success;  
}  
catch (Exception e) {   
    return failure;  
}  
finally {  
    System.out.println("I don't know if this will get printed out");
}

当前回答

以下是一些可以绕过finally块的条件:

如果在执行try或catch代码时JVM退出,那么finally块可能不会执行。更多太阳教程正常关闭-当最后一个非守护程序线程退出时,或者当Runtime.exit()(一些不错的博客)时,都会发生这种情况。当线程退出时,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

其他回答

我试过了,它是单线程的。

public static void main(String args[]) throws Exception {
    Object obj = new Object();
    try {
        synchronized (obj) {
            obj.wait();
            System.out.println("after wait()");
        }
    } catch (Exception ignored) {
    } finally {
        System.out.println("finally");
    }
}

主线程将永远处于等待状态,因此最终不会被调用,

因此控制台输出不会在wait()或finally之后打印String:

同意@Stephen C的观点,上述示例是这里提到的第三个案例之一:

在以下代码中添加更多这样的无限循环可能性:

// import java.util.concurrent.Semaphore;

public static void main(String[] args) {
    try {
        // Thread.sleep(Long.MAX_VALUE);
        // Thread.currentThread().join();
        // new Semaphore(0).acquire();
        // while (true){}
        System.out.println("after sleep join semaphore exit infinite while loop");
    } catch (Exception ignored) {
    } finally {
        System.out.println("finally");
    }
}

案例2:如果JVM首先崩溃

import sun.misc.Unsafe;
import java.lang.reflect.Field;

public static void main(String args[]) {
    try {
        unsafeMethod();
        //Runtime.getRuntime().halt(123);
        System.out.println("After Jvm Crash!");
    } catch (Exception e) {
    } finally {
        System.out.println("finally");
    }
}

private static void unsafeMethod() throws NoSuchFieldException, IllegalAccessException {
    Field f = Unsafe.class.getDeclaredField("theUnsafe");
    f.setAccessible(true);
    Unsafe unsafe = (Unsafe) f.get(null);
    unsafe.putAddress(0, 0);
}

参考:如何使JVM崩溃?

情况6:如果finally块将由守护程序线程执行,并且所有其他非守护程序线程在finally被调用之前退出。

public static void main(String args[]) {
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            try {
                printThreads("Daemon Thread printing");
                // just to ensure this thread will live longer than main thread
                Thread.sleep(10000);
            } catch (Exception e) {
            } finally {
                System.out.println("finally");
            }
        }
    };
    Thread daemonThread = new Thread(runnable);
    daemonThread.setDaemon(Boolean.TRUE);
    daemonThread.setName("My Daemon Thread");
    daemonThread.start();
    printThreads("main Thread Printing");
}

private static synchronized void printThreads(String str) {
    System.out.println(str);
    int threadCount = 0;
    Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
    for (Thread t : threadSet) {
        if (t.getThreadGroup() == Thread.currentThread().getThreadGroup()) {
            System.out.println("Thread :" + t + ":" + "state:" + t.getState());
            ++threadCount;
        }
    }
    System.out.println("Thread count started by Main thread:" + threadCount);
    System.out.println("-------------------------------------------------");
}

输出:这不会打印“finally”,这意味着“守护进程线程”中的“finally块”没有执行

主螺纹打印线程:线程[My Daemon线程,5,main]:状态:BLOCKED线程:线程[main,5,main]:状态:RUNNABLE线程:线程[Monitor Ctrl-Break,5,main]:状态:RUNNABLE主线程启动的线程计数:3------------------------------------------------- Daemon线程打印线程:线程[My Daemon线程,5,main]:状态:RUNNABLE线程:线程[Monitor Ctrl-Break,5,main]:状态:RUNNABLE主线程启动的线程计数:2------------------------------------------------- 进程已完成,退出代码为0

除非出现异常程序终止(如调用System.exit(0)..),否则始终执行finally。因此,将打印sysout

除其他响应外,重要的是要指出,“finally”有权通过try重写任何异常/返回值。。捕捉块。例如,以下代码返回12:

public static int getMonthsInYear() {
    try {
        return 10;
    }
    finally {
        return 12;
    }
}

类似地,以下方法不会引发异常:

public static int getMonthsInYear() {
    try {
        throw new RuntimeException();
    }
    finally {
        return 12;
    }
}

虽然以下方法确实抛出了它:

public static int getMonthsInYear() {
    try {
        return 12;          
    }
    finally {
        throw new RuntimeException();
    }
}

是的,finally将在执行try或catch代码块后调用。

唯一不会被调用的时间是:

如果调用System.exit()如果调用Runtime.getRuntime().hart(exitStatus)如果JVM首先崩溃如果JVM到达try或catch块中的无限循环(或其他一些不可中断、不终止的语句)如果操作系统强制终止JVM进程;例如,在UNIX上,kill-9<pid>如果主机系统失效;例如,电源故障、硬件错误、操作系统死机等如果finally块将由守护程序线程执行,并且所有其他非守护程序线程在finally调用之前退出

试用间苯二酚示例

static class IamAutoCloseable implements AutoCloseable {
    private final String name;
    IamAutoCloseable(String name) {
        this.name = name;
    }
    public void close() {
        System.out.println(name);
    }
}

@Test
public void withResourceFinally() {
    try (IamAutoCloseable closeable1 = new IamAutoCloseable("closeable1");
         IamAutoCloseable closeable2 = new IamAutoCloseable("closeable2")) {
        System.out.println("try");
    } finally {
        System.out.println("finally");
    }
}

测试输出:

try
closeable2
closeable1
finally