finally块总是运行吗?

有没有什么条件最终可能不会在Java中运行? 谢谢。

从Sun教程

注意:如果JVM在try或catch代码执行时退出,那么finally块可能不会执行。 同样,如果执行try或catch代码的线程被中断或终止,即使应用程序整体继续,finally块也可能不会执行。

我不知道任何其他方式的finally块不会执行…

System.exitclosures虚拟机。

终止当前运行的Java虚拟机。 这个论点是一个状态码。 按照惯例,非零状态码表示exception终止。

此方法在类Runtime调用exit方法。 此方法从不正常返回。

  try { System.out.println("hello"); System.exit(0); } finally { System.out.println("bye"); } // try-finally 

上面的代码中没有打印出“再见”。

只是为了扩展别人的说法,任何不会导致类似JVM退出的事情都会导致finally块。 所以下面的方法:

 public static int Stupid() { try { return 0; } finally { return 1; } } 

会奇怪的编译并返回1。

与System.exit相关,也有一些types的灾难性的失败,finally块可能无法执行。 如果JVM完全耗尽内存,它可能会在没有捕获或最终发生的情况下退出。

具体来说,我记得我们愚蠢地尝试使用的一个项目

 catch (OutOfMemoryError oome) { // do stuff } 

这不起作用,因为JVM没有留下执行catch块的内存。

 try { for (;;); } finally { System.err.println("?"); } 

在这种情况下,finally将不会执行(除非被弃用的Thread.stop被调用,或者通过一个工具接口,等价的)。

太阳教程在这里被错误地引用了。

注意:如果JVM在try或catch代码执行时退出,那么finally代码块不会执行。 同样,如果执行try或catch代码的线程被中断或终止,即使应用程序整体继续,finally块不会执行。

如果你仔细查看sun教程最后的阻止,它不会说“不会执行”,而是“不能执行”这是正确的描述

注意:如果JVM在try或catch代码执行时退出,那么finally块可能不会执行。 同样,如果执行try或catch代码的线程被中断或终止,即使应用程序整体继续,finally块不能执行。

这种行为的明显原因是,调用system.exit()在运行时系统线程中处理,这可能需要一些时间来closuresjvm,同时线程调度器可以最终要求执行。 所以最后的devise总是被执行,但是如果你closures了jvm,可能会发生jvm在最终被执行之前closures。

另外如果在try块内发生死锁/活锁。

以下是演示它的代码:

 public class DeadLocker { private static class SampleRunnable implements Runnable { private String threadId; private Object lock1; private Object lock2; public SampleRunnable(String threadId, Object lock1, Object lock2) { super(); this.threadId = threadId; this.lock1 = lock1; this.lock2 = lock2; } @Override public void run() { try { synchronized (lock1) { System.out.println(threadId + " inside lock1"); Thread.sleep(1000); synchronized (lock2) { System.out.println(threadId + " inside lock2"); } } } catch (Exception e) { } finally { System.out.println("finally"); } } } public static void main(String[] args) throws Exception { Object ob1 = new Object(); Object ob2 = new Object(); Thread t1 = new Thread(new SampleRunnable("t1", ob1, ob2)); Thread t2 = new Thread(new SampleRunnable("t2", ob2, ob1)); t1.start(); t2.start(); } } 

该代码产生以下输出:

 t1 inside lock1 t2 inside lock1 

和“终于”永远不会被打印

以下是一些可以绕过最后一个块的条件:

  1. 如果JVM在执行try或catch代码时退出,那么finally块可能不会执行。
  2. 正常关机 – 当最后一个非守护线程退出或Runtime.exit()
  3. 当线程退出时,JVM执行正在运行线程的清单,如果剩下的线程是守护进程线程,它将启动有序closures。 当JVM暂停时,任何剩余的守护进程线程被放弃,最终块不会被执行,堆栈不会退出JVM刚刚退出。 守护线程应该尽量less用处理活动,可以随时安全地放弃而不需要清理。 特别是对于可能执行任何I / O操作的任务使用守护线程是非常危险的。 守护进程线程最好保存为“内务”任务,例如定期从内存caching中删除过期条目的后台线程。

最后一个非守护线程退出示例:

 public class TestDaemon { private static Runnable runnable = new Runnable() { @Override public void run() { try { while (true) { System.out.println("Is alive"); Thread.sleep(10); // throw new RuntimeException(); } } catch (Throwable t) { t.printStackTrace(); } finally { System.out.println("This will never be executed."); } } }; public static void main(String[] args) throws InterruptedException { Thread daemon = new Thread(runnable); daemon.setDaemon(true); daemon.start(); Thread.sleep(100); // daemon.stop(); System.out.println("Last non-daemon thread exits."); } } 

输出:

 Is alive Is alive Is alive Is alive Is alive Is alive Is alive Is alive Is alive Is alive Last non-daemon thread exits. Is alive Is alive Is alive Is alive Is alive 

我遇到了一个非常特殊的情况,finally块并没有执行特定于玩框架的相关内容。

我很惊讶地发现,这个控制器动作代码中的finally块只在exception之后被调用,但从来没有调用成功的时候。

 try { InputStream is = getInputStreamMethod(); renderBinary(is, "out.zip"); catch (Exception e) { e.printStackTrace(); } finally { cleanUp(); } 

当调用renderBinary()时,线程可能会被终止。 我会怀疑同样的事情发生在其他render()调用,但我没有validation它。

我通过将renderBinary()移到try / catch之后解决了这个问题。 进一步的调查显示,play提供了@Finally注释来创build一个在控制器动作执行后被执行的方法。 这里需要注意的是,在控制器中执行ANY操作之后,会调用它,所以它可能并不总是一个好的select。

在以下情况下,finally块将不会被执行: –

  • 当从try块调用System.exit(0)时。
  • 当JVM耗尽内存时
  • 当你的java进程从任务pipe理器或控制台强行杀死
  • 死锁条件在你的尝试块
  • 当您的机器由于电源故障而closures时

也可能有其他的边缘情况,最终阻止不会被执行。

 //If ArithmeticException Occur Inner finally would not be executed class Temp { public static void main(String[] s) { try { int x = 10/s.length; System.out.println(x); try { int z[] = new int[s.length]; z[10] = 1000; }catch(ArrayIndexOutOfBoundsException e) { System.out.println(e); } finally { System.out.println("Inner finally"); } } catch(ArithmeticException e) { System.out.println(e); } finally { System.out.println("Outer Finally"); } System.out.println("Remaining Code"); } }