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

Java 为什么finally块中的语句仍在执行?,java,multithreading,try-catch-finally,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 In

结果

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();
}}
我试着从“Thinking in Java”第四版中获取代码示例,但没有得到书中描述的结果,finally块仍在执行,为什么会这样?顺便说一句,我使用的是OracleJDK10.0.1

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

似乎我的maven runner插件运行了一些东西,我禁用了它,结果与书中描述的一样。

应该一直运行吗。除非JVM实际停止
最后
块,否则保证进入。差不多

Starting ADaemon
Exiting via InterruptedException
This should always run?
中,catch
块将阻止该操作如果这就是你想要的。它还将停止JVM!这本书警告您,如果所有其他线程都已完成,则在JVM终止之前,守护进程线程可能永远不会被调度。您正在直接调用
start()
。考虑使用

System.exit(-1);

除非删除
t.setDaemon(true),否则它可能不会运行

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

SwingUtilities.invokeLater(t);

如果这是在一个方法中,那么finally块仍然会被执行(千万不要这样做,因为这是一个糟糕的做法)。它被设计为执行任何清理,不管您所做的操作的结果如何,例如关闭流(现在可以通过语句“try”中的parantise自动完成)。

您说这本书说:

“最后一个块可能无法执行”

(重点加上。)

这并不等于说:

“最终块将不会执行”

我认为这本书的意思是,当应用程序退出时,守护进程线程是否会得到中断(或其他什么)是未指定的(可能是JVM特定的)

当然,如果守护进程线程捕获并忽略了如下所示的“中断”异常,那么我希望
最终
永远不会执行

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

如果守护进程线程没有执行可中断的代码,我会预期类似的行为。

据我所知,即使出现异常,
finally
也应该运行。@Jai但在书中,当您将线程设置为守护进程时,finally块可能不会执行。令人惊讶的是,这里抛出了一个中断的异常。我无法在Java8中复制它,它的行为正如Bruce所说。这是openjdk吗?@NathanHughes这是oracle jdk 10.0.1。因为它位于
finally
块中。这就是他们的目的。但在书中,它说“守护进程线程将在不执行finally子句的情况下终止其run()方法”,书中的结果实际上是“启动Adaemon”,而不执行finally子句。为什么我的代码执行结果与书中的不同?现在的结果是“启动ADaemon,这应该一直运行吗?”,它没有捕获异常,但最终块仍在执行。@AlanLian当所有非守护进程线程结束时,JVM正常结束。此时,JVM将退出,而不等待守护进程线程结束,因此守护进程线程的调用堆栈不会展开,因此不会执行堆栈上的
finally
块。然而,当JVM结束时,如果守护进程线程中的代码返回,那么当然会执行
finally
块,因为它们必须执行,才能释放调用堆栈。@Andreas可以解释守护进程线程返回和未返回的线程之间的详细区别吗?我看不出有什么区别here@Alan:只是无论守护进程线程正常完成还是jvm死机,都可能是一种竞争条件。但是你的1秒睡眠时间似乎给了主线程足够的时间来终止。实际上我在问为什么我的结果和书中的结果有差异。不管怎样,谢谢你的回答。这就是我想说的,它在大多数情况下都会运行,即使在你的情况下也是如此。但是正如Nathan Hughes在评论中所说,jdk 8中的这个示例产生的结果与Bruce所说的相同,为什么我的不同?@AlanLian显而易见的答案是Oracle在Java 8和Java 10之间改变了一些东西。@Powerlord u是对的。但我想知道是什么变化导致了这种差异。这本书最初说“您应该知道守护进程线程将在不执行finally子句的情况下终止其run()方法”。为了描述这种情况,我的表达式在这里可能有点模棱两可。但我想这本书是想说,如果最后一个非守护进程线程终止,那么不管是否执行了finally块,它都会终止所有守护进程线程。如果这本书是这么说的,那么它(技术上)是不完整/不准确的,因为实际行为可能取决于守护进程线程对中断的响应。(教训:书本可能是错误的。只相信规范所说的。)谢谢,但是你有关于守护进程线程响应中断将做什么的进一步阅读吗?
thread
javadocs将是一个很好的开始。(行为与非守护进程线程相同。)Thx。顺便说一句,jdk 8和jdk 10似乎有不同的结果,所以它可能与版本更改有一些关系。
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();
    }
}