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

时间:2013-01-29 06:16:04

标签: java multithreading try-catch interrupt interruption

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

6 个答案:

答案 0 :(得分:8)

According to the Java Tutorials,"如果执行trycatch代码的线程被中断或终止,finally块可能无法执行,即使应用程序为一个整体继续。"

这里有完整的段落:

  

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();

打印 - 最后执行

答案 1 :(得分:4)

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

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

答案 2 :(得分:4)

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

首先,Java中的线程中断与OS级别的中断无关。 Sharing a name creates opportunities for confusion but there is no connection

接下来,JVM退出显然会杀死线程而没有机会进行任何清理。如果进程在线程到达finally块之前就已经死了,那就太糟糕了。但是没有比较中断。关于中断的任何事情都无法阻止最终的阻止。

中断的设计原则是作用于中断需要被中断的线程的协作。线程中断响应自行决定,中断不会强制线程做任何事情。所有调用Thread#interrupt()都会在线程上设置一个标志。阻止等待或睡眠的方法检查标志,看看它们是否应该提早醒来。 (InterruptedException是一个经过检查的异常,因此您可以告诉谁在什么时候抛出它,并且您的Runnable可以为它进行规划。)此外,任何代码都可以使用Thread#isInterrupted()来检查其线程是否已设置标记。

当Thread#sleep()识别出设置了中断标志时,它会在抛出InterruptedException之前清除该标志。当你的线程捕获InterruptedException时,使用Thread.currentThread()。interrupt()恢复标志是很好的方式,以防万一在该线程中运行任何需要了解中断的其他代码。当你有更复杂的嵌套同步器情况时会发挥作用,例如,某些深度嵌套的组件可能会使其睡眠中断,让它保持清除可能会阻止更高层知道中断。在一个简单的玩具示例中,如此处的其他答案中的那些,如果标志是否恢复并不重要,则不会再次检查它并且线程终止。

答案 3 :(得分:3)

commentsanswer,@ Risadinha询问了一个非常有效的问题,即如果我们通过调用恢复finally块内的中断标志,catch块中的代码是否会被执行Thread.currentThread().interrupt()

以下是要测试的小代码段:

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 SomeContext {
    public volatile int value = 10;
}

答案 4 :(得分:1)

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

答案 5 :(得分:0)

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