101

Is there any condition where finally might not run in java? Thanks.


  • Is this a question you might get asked when trying to get a job with a certain well known company? - Tom Hawtin - tackline
  • @TomHawtin-tackline Care to name it? (God, I missed how old this post was!) - Hele
  • @Hele I wouldn't want to give the game away, but you can google it. - Tom Hawtin - tackline

12 답변


127

from the Sun Tutorials

Note: If the JVM exits while the try or catch code is being executed, then the finally block may not execute. Likewise, if the thread executing the try or catch code is interrupted or killed, the finally block may not execute even though the application as a whole continues.

I don't know of any other ways the finally block wouldn't execute...


  • @dhiller - I'm pretty sure that "power down" is included in "If the JVM exits..." :-p - Jason Coco
  • @Jason Coco: Terminating (as upon loss of power) is not quite the same thing as exiting; the latter is a more or less organized process culminating in the former. ;p - user359996
  • AFAIK, if a thread is interrupted, it's not immediately halted. It's up to the code in the thread to detect interruption and stop its task, so finally code should run. - Bart van Heukelom
  • I guess that if an exception is thrown in the finally block, the rest of the block is not executed. - Adriaan Koster
  • well that sucks! - eiran

58

System.exit shuts down the Virtual Machine.

Terminates the currently running Java Virtual Machine. The argument serves as a status code; by convention, a nonzero status code indicates abnormal termination.

This method calls the exit method in class Runtime. This method never returns normally.

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

"bye" does not print out in above code.


  • Also an exception should shut down the Java Virtual Machine. - kaissun
  • If an Exception occur while executing System.exit(0), then finally block will execute though. - halil

47

Just to expand on what others have said, anything that does not cause something like the JVM exiting will incur the finally block. So the following method:

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

will strangely both compile and return 1.


  • this really confused me for a good couple of hours a few weeks back. - nickf
  • It's considered a bad idea to return a value from a finally block. Either return only from the try block, or return from outside the try/finally block. Most IDEs will mark this with a warning. - Ran Biron
  • @nickf I gather that you are no longer confused. Could you elaborate on the mechanics of why 1 is returned and not 0. I could only guess that the memory (or is it a register) which stores the return value of the function that initially holds 0, is overwritten as the finally block is executed. - Yaneeve
  • That's curious, in C# it isn't allowed to return from a finally block. - JMCF125
  • @RanBiron Of course. He wasn't actually recommending returning inside a finally block, he was only trying to demonstrate that even a return statement will still cause code in said block to execute. - Aquarelle

14

Related to System.exit, there are also certain types of catastrophic failure where a finally block may not execute. If the JVM runs out of memory entirely, it may just exit without catch or finally happening.

Specifically, I remember a project where we foolishly tried to use

catch (OutOfMemoryError oome) {
    // do stuff
}

This didn't work because the JVM had no memory left for executing the catch block.


  • When OutOfMemoryError is thrown there is usually lots of memory left (to stop GC thrashing). However, if you catch it repeatedly you obviously will get back to GC thrashing. - Tom Hawtin - tackline
  • I thought one shouldn't catch unchecked exceptions! - Sergii Shevchyk
  • I tried in my side, using jdk7, but it did catch the OutOfMemory Error ! - Jaskey

9

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

In that case the finally will not execute (unless the deprecated Thread.stop is called, or an equivalent, say, through a tools interface).


  • This page claims that a ThreadDeath error is thrown, and that the stack unwinds normally when Thread.stop() is called. Is there a catch that I am missing? download.oracle.com/docs/cd/E17476_01/javase/1.5.0/docs/guide/… - spurserh
  • I don't think there's a catch. Perhaps there you are imagining a catch that isn't there. If we put in an explicit throw, then the finally block will execute as expected. try { throw new ThreadDeath(); } finally { System.err.println("?"); } - Tom Hawtin - tackline

7

The Sun tutorial has been wrongly quoted here in this thread.

Note: If the JVM exits while the try or catch code is being executed, then the finally block will not execute. Likewise, if the thread executing the try or catch code is interrupted or killed, the finally block will not execute even though the application as a whole continues.

If you look into sun tutorial closely for finally block, it doesn't say "will not execute" but "may not execute" Here is the correct description

Note: If the JVM exits while the try or catch code is being executed, then the finally block may not execute. Likewise, if the thread executing the try or catch code is interrupted or killed, the finally block may not execute even though the application as a whole continues.

The apparent reason for this behavior is, call to system.exit() is processed in a runtime system thread which may take time to shutdown the jvm, meanwhile thread scheduler can ask finally to execute. So finally is designed to always execute, but if you are shutting down jvm, it may happen that jvm shuts down prior to finally getting being executed.


5

Also if a deadlock/livelock happens inside try block.

Here's the code that demonstrates it:

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

This code produces the following output:

t1 inside lock1
t2 inside lock1

and "finally" never gets printed


  • Technically, the try block never exits so the finally block should never get a chance to execute. The same could be said for an infinite loop. - Jeff Mercado

4

Here are some conditions which can bypass a finally block:

  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.

Last non-daemon thread exits example:

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

Output:

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


0

I've come across a very specific case of the finally block not executing related specifically to the play framework.

I was surprised to find that the finally block in this controller action code only got called after an Exception, but never when the call actually succeeded.

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

Perhaps the thread is terminated or something when renderBinary() is called. I would suspect the same thing happens for other render() calls, but I didn't verify it.

I solved the problem by moving the renderBinary() to after the try/catch. Further investigation revealed that play provides an @Finally annotation to create a method that gets executed after a controller action executes. The caveat here is that this will get called after the execution of ANY action in the controller, so it may not always be a good choice.


0

In following cases, finally block will not be executed :-

  • When System.exit(0) is invoked from try block.
  • When JVM runs out of memory
  • When your java process is killed forcefully from task mgr or console
  • Deadlock condition in your try block
  • When your machine shuts down due power failure

There may also be other fringe cases, where finally block will not be executed.


0

There are two ways to stop finally block code execution:
1. Use System.exit();
2. If somehow execution control don't reach to try block.
See:

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


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


  • Improve the indentation and add some details. - ROMANIA_engineer
  • The execution wouldn't even get to the inner try block, of course the inner finally would not be executed. - Anton Arhipov

Linked


Related

Latest