如果运行该函数的线程被中断,finally块是否会执行?
如果我有一个带有try / finally部分的函数,并且运行它的线程在try块中被中断,那么finally块是否会在中断实际发生之前执行?
根据Java Tutorials ,“如果执行try
或catch
代码的线程被中断或finally
即使整个应用程序继续执行, finally
块也可能无法执行。”
这是完整的段落:
当
try
块退出时,finally
块总是执行。 这确保即使发生意外exception也会执行finally
块。 但finally
不仅仅是exception处理有用 – 它允许程序员避免因return
,continue
或break
意外绕过清理代码。 将清理代码放在finally
块中总是一种很好的做法,即使没有预期的例外情况也是如此。注意:如果在执行
try
或catch
代码时JVM退出,则finally
块可能无法执行。 同样,如果执行try
或catch
代码的线程被中断或finally
,则即使应用程序作为一个整体继续,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();
它打印 – 最后执行
Java中的线程中断只是设置一个标志。 它不会对当前正在执行的代码造成任何特殊情况,或影响控制流。
如果你的线程参与或试图进入一个抛出InterruptedException的操作,那么从调用该方法的点抛出exception,如果它在try块内,则finally将在exception离开之前执行,就像正常一样。
Oracle的许多Java教程都很有帮助(我的答案引用了受保护的块页面和SAX介绍),但它们不一定是权威的,有些错误或不完整。 问题中引用的引用将中断与JVM退出混淆,这令人困惑。
首先,Java中的线程中断与OS级别的中断无关。 共享名称会产生混淆的机会,但没有联系 。
接下来,JVM退出显然会杀死线程而没有机会进行任何清理。 如果进程在线程到达finally块之前就已经死了,那就太糟糕了。 但是没有比较中断。 关于中断没有任何阻止最终阻止完成。
中断的设计原则是作用于中断需要被中断的线程的协作。 线程中断响应自行决定,中断不会强制线程做任何事情。 所有调用Thread#interrupt()都会在线程上设置一个标志。 阻止等待或睡眠的方法检查标志,看看它们是否应该提早醒来。 (InterruptedException是一个已检查的exception,因此您可以告诉谁何时抛出它,并且您的Runnable可以为它进行规划。)此外,任何代码都可以使用Thread#isInterrupted()来检查其线程是否已设置标志。
当Thread#sleep()识别出设置了中断标志时,它会在抛出InterruptedException之前清除该标志。 当你的线程捕获InterruptedException时,使用Thread.currentThread()。interrupt()恢复标志是很好的方法,以防万一在该线程中运行任何需要知道中断的其他代码。 当你有更复杂的嵌套同步器情况时会发挥作用,例如,一些深层嵌套的组件可能会使其睡眠中断,让它保持清除可以防止更高层知道中断。 在一个简单的玩具示例中,如此处其他答案中的那些,如果标志是否已恢复无关紧要,则不会再次检查它并且线程终止。
在回答的评论中,@ Risadinha问了一个非常有效的问题,即如果我们通过调用Thread.currentThread().interrupt()
恢复catch
块中的中断标志,是否会执行finally
块中的代码。
以下是要测试的小代码段:
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; }
中断的影响是在下次发生阻塞操作时抛出InterruptedException
(实际上,下次调用一个方法时指定它可以抛出InterruptedException
),此时 – 正常情况下 – 正常的try/catch
遵循执行流程,它确实在try
和任何适用的catch
es之后执行finally
块。
它将以与try块中的任何其他exception相同的方式执行,而不是在中断之前执行。