Каковы обстоятельства, при которых блок finally {} не будет выполняться?

в Java try{} ... catch{} ... finally{} блок, код внутри finally{} обычно считается "гарантированным" для запуска независимо от того, что происходит в try/catch. Однако, я знаю по крайней мере два обстоятельства, при которых он будет не выполнить:

  • если System.exit(0) называется; или
  • если исключение брошено полностью до JVM и происходит поведение по умолчанию (т. е. printStackTrace() и выход)

есть ли какие-либо другие поведения программы, которые предотвратит код в finally{} блок от выполнения? При каких конкретных условиях будет выполняться код или нет?

EDIT: как указал NullUserException, второй случай на самом деле не верен. Я думал, это потому, что текст в стандартной ошибке печатается после этого в standard out, предотвращая просмотр текста без прокрутки. :) Извинения.

9 ответов


если вы называете System.exit() программа немедленно завершает работу без finally называют.

сбой JVM, например, ошибка сегментации, также предотвратит окончательный вызов. т. е. JVM немедленно останавливается на этом этапе и создает отчет о сбое.

бесконечный цикл также предотвратит окончательный вызов.

блок finally всегда вызывается, когда выбрасывается Throwable. Даже если вы вызываете поток.stop (), который запускает ThreadDeath быть брошенным в целевой поток. Это можно поймать (это Error) и блок finally будет вызван.


public static void main(String[] args) {
    testOutOfMemoryError();
    testThreadInterrupted();
    testThreadStop();
    testStackOverflow();
}

private static void testThreadStop() {
    try {
        try {
            final Thread thread = Thread.currentThread();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    thread.stop();
                }
            }).start();
            while(true)
                Thread.sleep(1000);
        } finally {
            System.out.print("finally called after ");
        }
    } catch (Throwable t) {
        System.out.println(t);
    }
}

private static void testThreadInterrupted() {
    try {
        try {
            final Thread thread = Thread.currentThread();
            new Thread(new Runnable() {
                @Override
                public void run() {
                    thread.interrupt();
                }
            }).start();
            while(true)
                Thread.sleep(1000);
        } finally {
            System.out.print("finally called after ");
        }
    } catch (Throwable t) {
        System.out.println(t);
    }
}

private static void testOutOfMemoryError() {
    try {
        try {
            List<byte[]> bytes = new ArrayList<byte[]>();
            while(true)
                bytes.add(new byte[8*1024*1024]);
        } finally {
            System.out.print("finally called after ");
        }
    } catch (Throwable t) {
        System.out.println(t);
    }
}

private static void testStackOverflow() {
    try {
        try {
            testStackOverflow0();
        } finally {
            System.out.print("finally called after ");
        }
    } catch (Throwable t) {
        System.out.println(t);
    }
}

private static void testStackOverflow0() {
    testStackOverflow0();
}

печать

finally called after java.lang.OutOfMemoryError: Java heap space
finally called after java.lang.InterruptedException: sleep interrupted
finally called after java.lang.ThreadDeath
finally called after java.lang.StackOverflowError

Примечание: В каждом случае поток продолжал работать, даже после этого, OOME, Прерванный и поток.стоп!


бесконечный цикл в try заблокировать.

поврежден оперативной памяти? Программа больше не работает так, как написано? Я действительно отладил это однажды на машине DOS.


существует вероятность частичного выполнения, когда, наконец, сам выдает исключение (или приводит к ошибке)


может быть "a, наконец, является частью потока daeomon, он не может быть выполнен".


единственный раз, наконец, не будет называться:

Если питание отключается

  1. если вы вызываете систему.exit ()
  2. если JVM падает первым
  3. если есть бесконечный цикл в try блок
  4. если питание отключается

тестирование наконец-то блок в другом операторе в блоке try.

 public static void main(String [] args){

    try{
        System.out.println("Before Statement");
        /*** Statement ***/
        System.out.println("After Statement");
    }
    catch(Exception e){
    }
    finally{
        System.out.println("Finally is Executed");
    }

заявления, в котором finally блок выполняется следующие:

  1. Thread.currentThread().interrupted();
  2. Thread.currentThread().destroy();
  3. Thread.currentThread().stop();
  4. Thread.sleep(10);
  5. Thread.currentThread().interrupt();
  6. Runtime.getRuntime().addShutdownHook(Thread.currentThread());
  7. если произошло какое-либо исключение.
  8. если нет исключение.

заявления, в котором блок finally не выполняется следующие:

  1. Thread.currentThread().suspend();
  2. System.exit(0);
  3. JVM-машине разбился.
  4. питание чипа CPU отключается.
  5. OS убивает процесс JVM.
  6. Runtime.getRuntime().exit(0);
  7. Runtime.getRuntime().halt(0);

Я думаю, что когда JVM внезапно выходит по какой-либо причине, это может быть причиной того, что элемент управления не войдет в блок finally и никогда не будет выполняться.


Вы можете сделать его частью потока демона. Вы можете использовать метод setDaemon(boolean status) который используется для обозначения текущего потока как потока демона или пользовательского потока и выхода из JVM по мере необходимости. Это позволит вам выйти из JVM до finally{} выполняется.


другой возможный экземпляр блока finally, который никогда не будет выполняться, будет связан с дизайном, в котором метод возвращается до ввода блока try, как в случае очень плохого кода, который я видел время от времени:

public ObjectOfSomeType getMeAnObjectOfSomeType() throws SomeHorrendousException {
    if (checkSomeObjectState()) {
        return new ObjectOfSomeType();
    }

    try {
        // yada yada yada...
    } catch (SomeHorrendousException shexc) {
        // wow, do something about this horrendous exception...
    } finally {
        // do some really important cleanup and state invalidation stuff...
    }

Я знаю, что никто из вас никогда бы этого не сделал, поэтому я колебался добавить это как возможный сценарий, но подумал, Эх, это пятница, какого черта;)