java 如果运行该函数的线程被中断,finally 块是否执行?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14576765/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 16:44:16  来源:igfitidea点击:

Does the finally block execute if the thread running the function is interrupted?

javamultithreadingtry-catchinterruptinterruption

提问by user940016

If I have a function with a try/finally section, and the thread running it is interrupted while in the try block, will the finally block execute before the interruption actually occurs?

如果我有一个带有 try/finally 部分的函数,并且运行它的线程在 try 块中被中断,finally 块会在中断实际发生之前执行吗?

采纳答案by Subhrajyoti Majumder

According to the Java Tutorials, "if the thread executing the tryor catchcode is interrupted or killed, the finallyblock may not execute even though the application as a whole continues."

根据 Java 教程,“如果执行trycatch代码的线程被中断或终止,finally即使应用程序作为一个整体继续运行,块也可能不会执行。”

Here's the full passage:

这是完整的段落:

The finallyblock alwaysexecutes when the tryblock exits. This ensures that the finallyblock is executed even if an unexpected exception occurs. But finallyis useful for more than just exception handling — it allows the programmer to avoid having cleanup code accidentally bypassed by a return, continue, or break. Putting cleanup code in a finallyblock is always a good practice, even when no exceptions are anticipated.

Note:If the JVM exits while the tryor catchcode is being executed, then the finallyblock may not execute. Likewise, if the thread executing the tryor catchcode is interrupted or killed, the finallyblock may not execute even though the application as a whole continues.

finally始终执行时try块退出。这确保finally即使发生意外异常,块也能执行。但是,finally是的不仅仅是异常处理更加有用-它允许程序员避免不慎被绕过具有清除代码returncontinuebreak。将清理代码放在一个finally块中始终是一个好习惯,即使没有预料到异常也是如此。

注意:如果在执行trycatch代码时JVM 退出,则该finally块可能不会执行。同样,如果执行trycatch代码的线程被中断或终止,finally即使应用程序作为一个整体继续运行,块也可能不会执行。

class Thread1 implements Runnable {

    @Override
    public void run() {
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            System.out.println("finally executed");
        }
    }
}

...

...

t1.start();
t1.interrupt();

It prints- finally executed

它打印- 最后执行

回答by Affe

A Thread Interrupt in Java is just setting a flag. It doesn't cause anything special to happen to currently executing code, or affect the flow of control.

Java 中的线程中断只是设置一个标志。它不会导致当前正在执行的代码发生任何特殊情况,也不会影响控制流。

If your thread is engaged in, or attempts to enter, an operation that throws InterruptedException, then the exception is thrown from the point where that method is invoked and if it's inside a try block, the finally will execute before the exception leaves just like normal.

如果您的线程正在参与或试图进入抛出 InterruptedException 的操作,则从调用该方法的点抛出异常,如果它在 try 块内,则 finally 将在异常离开之前执行,就像正常一样.

回答by Nathan Hughes

Many of Oracle's Java tutorials are helpful (I have answers referencing the guarded blocks page and the SAX introduction), but they are not necessarily authoritative, and some of them have mistakes or are incomplete. The quote referenced in the question conflates interruption with the JVM exiting, which is confusing.

Oracle 的许多 Java 教程很有帮助(我参考了受保护的块页面和 SAX 介绍的答案),但它们不一定具有权威性,并且其中一些有错误或不完整。问题中引用的引用将中断与 JVM 退出混为一谈,这令人困惑。

First, thread interruption in Java has nothing to do with OS-level interrupts. Sharing a name creates opportunities for confusion but there is no connection.

首先,Java 中的线程中断与操作系统级中断无关。共享名称会造成混淆,但没有任何联系

Next, JVM exit obviously kills the thread without an opportunity to do any cleanup. If the process dies before the thread has gotten as far as the finally block, too bad. But there's no comparison to interruption. Nothing about interruption prevents finally blocks from completing.

接下来,JVM 退出显然会在没有机会进行任何清理的情况下杀死线程。如果进程在线程到达 finally 块之前就死了,那就太糟糕了。但与中断没有可比性。中断不会阻止 finally 块完成。

A design principle of interruption is that acting on the interruption requires the cooperation of the thread being interrupted. The thread interrupted responds at its discretion, the interruption doesn't compel the thread to do anything. All calling Thread#interrupt() does is set a flag on the thread. Blocking methods like wait or sleep check the flag to see if they should wake up early. (InterruptedException is a checked exception so you can tell who throws it when, and your Runnable can plan for it.) Also any code can use Thread#isInterrupted() to check whether its thread has had the flag set.

中断的一个设计原则是作用于中断需要被中断线程的配合。被中断的线程自行决定响应,中断不会强迫线程做任何事情。所有调用 Thread#interrupt() 所做的都是在线程上设置一个标志。诸如等待或睡眠之类的阻塞方法检查标志以查看它们是否应该早起。(InterruptedException 是一个已检查的异常,所以你可以知道谁在什么时候抛出它,你的 Runnable 可以计划它。)此外,任何代码都可以使用 Thread#isInterrupted() 来检查它的线程是否设置了标志。

When Thread#sleep() recognizes the interrupted flag is set, it clears the flag before throwing InterruptedException. When your thread catches an InterruptedException it's good manners to restore the flag using Thread.currentThread().interrupt(), just in case there is any other code running in that thread that needs to know about the interruption. This comes into play when you have more complex situations with nested synchronizers where, for instance, some deeply nested component could get its sleep interrupted, letting it stay cleared could prevent higher layers from knowing about the interruption. In a simple toy example like the ones in other answers here, it doesn't matter if the flag is restored or not, nothing checks it again and the thread terminates.

当 Thread#sleep() 识别出已设置中断标志时,它会在抛出 InterruptedException 之前清除该标志。当您的线程捕获到 InterruptedException 时,使用 Thread.currentThread().interrupt() 恢复标志是一种很好的方式,以防万一该线程中运行的任何其他代码需要了解中断。当您遇到嵌套同步器的更复杂情况时,这会起作用,例如,某些深度嵌套的组件可能会中断其睡眠,让它保持清除状态可以防止更高层知道中断。在一个简单的玩具示例中,就像这里其他答案中的示例一样,标志是否恢复都没有关系,没有任何东西再次检查它并且线程终止。

回答by Keenle

In the commentsto the answer, @Risadinha asked very valid question about whether code in finallyblock gets executed if we restore interruption flag inside catchblock by calling Thread.currentThread().interrupt().

在对答案评论中,@Risadinha 提出了一个非常有效的问题,即如果我们通过调用.finallycatchThread.currentThread().interrupt()

Here is small code snippet to test:

这是要测试的小代码片段:

final SomeContext context = new SomeContext();
Thread thread = new Thread() {
    @Override
    public void run() {
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            // this code gets executed even though
            // we interrupt thread in catch block.
            context.value = 9;  
        }
    }
};

thread.start();
thread.interrupt();

thread.join(); // need to wait for thread code to complete

assertEquals(context.value, 9); // values are the same!

SomeContext class code:

SomeContext 类代码:

class SomeContext {
    public volatile int value = 10;
}

回答by Louis Wasserman

The effect of interruption is to throw an InterruptedExceptionthe next time a blocking operation occurs (in practice, the next time a method is called that specifies it can throw an InterruptedException), at which point -- as usual -- the normal try/catchexecution flow is followed, which does indeed execute the finallyblock after the tryand any applicable catches.

中断的效果是InterruptedException在下一次发生阻塞操作时抛出一个(实际上,下一次调用指定它可以抛出一个的方法时InterruptedException),此时 - 像往常一样 -try/catch遵循正常的执行流程,它确实finally在estry和任何适用的catches之后执行块。

回答by jdb

It will execute the same way as with any other exception from the try block, not before the interruption.

它将以与 try 块中的任何其他异常相同的方式执行,而不是在中断之前。