finally块总是运行吗?

时间:2009-01-21 04:38:24

标签: java finally

是否有任何条件最终可能无法在java中运行?感谢。

12 个答案:

答案 0 :(得分:136)

来自Sun Tutorials

  

注意:如果JVM在尝试时退出   或者正在执行catch代码   finally块可能无法执行。   同样,如果线程执行   尝试或捕获代码被中断或   杀了,终于阻止了   即使应用程序执行也执行   整体还在继续。

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

答案 1 :(得分:62)

System.exit关闭虚拟机。

  

终止当前运行的Java   虚拟机。这个论点有用   作为状态代码;按惯例,a   非零状态代码表示异常   终止。

     

此方法调用exit方法   班Runtime。从来没有这种方法   正常回归。

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

“bye”不会在上面的代码中打印出来。

答案 2 :(得分:49)

为了扩展其他人所说的内容,任何不会导致JVM退出的事情都将导致finally块。所以方法如下:

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

奇怪地编译并返回1。

答案 3 :(得分:15)

与System.exit相关,还存在某些类型的灾难性故障,其中finally块可能无法执行。如果JVM完全耗尽内存,它可能会在没有捕获或最终发生的情况下退出。

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

的项目
catch (OutOfMemoryError oome) {
    // do stuff
}

这不起作用,因为JVM没有剩余的内存来执行catch块。

答案 4 :(得分:10)

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

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

答案 5 :(得分:8)

此主题中错误地引用了Sun教程。

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

如果你仔细研究sun教程中的finally块,它不会说“不会执行”但是“可能不会执行” 这是正确的描述

  

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

这种行为的明显原因是,在运行时系统线程中处理对system.exit()的调用,这可能需要一些时间来关闭jvm,同时线程调度程序可以最终要求执行。因此最终设计为始终执行,但如果您正在关闭jvm,则可能会发生jvm在最终执行之前关闭。

答案 6 :(得分:6)

此外,如果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

和“finally”永远不会被打印

答案 7 :(得分:5)

以下是一些可以绕过finally块的条件:

  1. If the JVM exits while the try or catch code is being executed, then the finally block may not execute.
  2. Normal Shutdown - this occurs either when the last non-daemon thread exits OR when Runtime.exit()
  3. When a thread exits, the JVM performs an inventory of running threads, and if the only threads that are left are daemon threads, it initiates an orderly shutdown. When the JVM halts, any remaining daemon threads are abandoned finally blocks are not executed, stacks are not unwound the JVM just exits. Daemon threads should be used sparingly few processing activities can be safely abandoned at any time with no cleanup. In particular, it is dangerous to use daemon threads for tasks that might perform any sort of I/O. Daemon threads are best saved for "housekeeping" tasks, such as a background thread that periodically removes expired entries from an in-memory cache.
  4. 最后一个非守护程序线程退出示例:

    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
    

答案 8 :(得分:1)

有两种方法可以停止最终阻止代码执行:
 1.使用System.exit();
 2.如果执行控制无法达到尝试阻止的目的。
参见:

public class Main
{
  public static void main (String[]args)
  {
    if(true){
        System.out.println("will exceute");
    }else{
        try{
            System.out.println("result = "+5/0);
        }catch(ArithmeticException e){
          System.out.println("will not exceute");
        }finally{
          System.out.println("will not exceute");  
        }
    }
  }
}

答案 9 :(得分:0)

我遇到了一个非常具体的例子,即finally块没有专门针对play框架执行。

我很惊讶地发现此控制器动作代码中的finally块仅在异常后调用,但从未在调用实际成功时调用。

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

调用renderBinary()时,可能会终止线程或者某些东西。我怀疑其他render()调用会发生同样的事情,但我没有验证它。

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

答案 10 :(得分:0)

在下列情况下,最终将不执行阻止: -

  • System.exit(0)块调用try时。
  • 当JVM内存不足时
  • 当你的java进程被强制从任务管理器或控制台
  • 中杀死时
  • try区块中的死锁条件
  • 当您的机器因电源故障而关闭时

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

答案 11 :(得分:-1)

//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");   
}
}