为什么finally块中的语句仍然执行?

时间:2018-07-23 02:27:20

标签: java multithreading try-catch-finally

public class ADaemon implements Runnable {
@Override
public void run() {
    try {
        System.out.println("Starting ADaemon");
        TimeUnit.SECONDS.sleep(1);
    } catch (InterruptedException e) {
        System.out.println("Exiting via InterruptedException");
    } finally {
        System.out.println("This should always run?");
    }
}

public static void main(String... args) {
    Thread t = new Thread(new ADaemon());
    t.setDaemon(true);
    t.start();
}}

结果

Starting ADaemon
Exiting via InterruptedException
This should always run?

我尝试使用“ Thinking in Java”第4版中的代码示例,但没有得到书中所述的结果,finally块仍在执行,为什么会这样?顺便说一句,我正在使用oracle jdk 10.0.1。

-------------更新----------

我的maven-runner插件似乎正在运行某些东西,我禁用了它,并且得到的效果与书中所述相同。

3 个答案:

答案 0 :(得分:3)

您说这本书说:

  

“可能无法执行 finally块

(添加了强调。)

那不是说:

  

“将不会执行finally块

我认为这本书暗示着,当应用程序退出时,守护进程线程是否会获得中断(或某种中断),这是未指定的(可能还特定于JVM)。

当然,如果守护程序线程按如下所示捕获并忽略了“中断的”异常,那么我会期望finally永远不会执行。

public class ADaemon implements Runnable {
    @Override
    public void run() {
        try {
            System.out.println("Starting ADaemon");
            while (true) {
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    System.out.println("Caught InterruptedException");
                }
            }
        } finally {
            System.out.println("This should always run?");
        }
    }

    public static void main(String... args) {
        Thread t = new Thread(new ADaemon());
        t.setDaemon(true);
        t.start();
    }
}

如果守护线程未执行可中断代码,我会期望类似的行为。

答案 1 :(得分:2)

这应该总是运行吗? 。除非JVM实际停止,否则将{strong>保证输入该块finally

System.exit(-1);
catch块中的

可以防止这种情况。 如果是您想要的。它还将停止JVM!这本书警告您,如果所有其他线程都已完成,则可能永远不会在JVM终止之前调度守护程序线程。您正在直接致电start()。考虑使用

SwingUtilities.invokeLater(t);

除非您删除t.setDaemon(true);

,否则它可能不会运行

答案 2 :(得分:0)

finally块是一个功能强大的工具(如果使用不当,将会很危险),它会在try或catch块完成后(尽管上面突出显示了一些小情况)几乎总是运行。 看这个例子:

try{
  throw new Exception();
}catch(Exception e){
return;
}finally{
System.out.println("Shouldn't run?");
}

如果这是在方法中,则将执行finally块 still (切勿执行此操作,因为这是一种不好的做法)。尽管您执行了诸如关闭流之类的操作,但它仍然可以执行任何清除操作(现在可以通过语句“ try”中的括号自动完成此操作)。