Всегда ли выполняется блок finally?

Есть ли какое-либо условие, в котором, наконец, не может быть запущено в java? Спасибо.

Ответ 1

из Sun Tutorials

Примечание. Если JVM выходит во время попытки или код catch, тогда блок finally может не выполняться. Аналогично, если поток, выполняющий попытка или уловка кода прерывается или убит, блок finally может не выполняются, хотя приложение как целое продолжается.

Я не знаю других путей, которые блок finally не выполнил бы...

Ответ 2

System.exit отключает виртуальную машину.

Завершает работу Java Виртуальная машина. Аргумент служит как код состояния; по соглашению, ненулевой код состояния указывает на ненормальный прекращение.

Этот метод вызывает метод exit в класс Runtime. Этот метод никогда обычно возвращается.

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

"bye" не распечатывается в приведенном выше коде.

Ответ 3

Просто чтобы расширить то, что говорили другие, все, что не вызывает что-то вроде выхода JVM, повлечет за собой окончательный блок. Итак, следующий метод:

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

будет странно компилироваться и возвращаться.

Ответ 4

В связи с System.exit существуют также некоторые типы катастрофических сбоев, когда блок finally может не выполняться. Если JVM полностью исчерпал память, он может просто выйти без catch или, наконец, произойти.

В частности, я помню проект, в котором мы глупо пытались использовать

catch (OutOfMemoryError oome) {
    // do stuff
}

Это не сработало, потому что у JVM не осталось памяти для выполнения блока catch.

Ответ 5

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

В этом случае, наконец, не будет выполняться (если не вызывается устаревший Thread.stop или эквивалент, скажем, через интерфейс инструментов).

Ответ 6

Учебник Sun был неправильно указан здесь в этом потоке.

Примечание. Если JVM завершает работу, пока выполняется код try или catch, тогда блок finally будет не выполнен. Аналогично, если поток, выполняющий код try или catch, прерван или убит, блок finally будет не выполняться, даже если приложение в целом продолжается.

Если вы внимательно изучаете учебник по солнцу для окончательного блока, он не говорит "не выполнит", но "может не выполнить", Вот правильное описание

Примечание. Если JVM завершает работу, пока выполняется код try или catch, блок finally может не выполнять. Аналогично, если поток, выполняющий код try или catch, прерван или убит, блок finally может не выполнять, даже если приложение в целом продолжается.

Очевидная причина такого поведения заключается в том, что вызов system.exit() обрабатывается в системном потоке времени выполнения, который может занять время, чтобы выключить jvm, между тем планировщик потоков может попросить, наконец, выполнить. Так что, наконец, он предназначен для выполнения всегда, но если вы закрываете jvm, может случиться, что jvm отключится, прежде чем, наконец, будет выполняться.

Ответ 7

Также, если в блоке 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" никогда не печатаются

Ответ 8

Вот некоторые условия, которые могут обходить блок finally:

Последний пример не-демона выходит:

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

Ответ 9

Я столкнулся с очень конкретным случаем блока finally, который не выполняется специально для платформы воспроизведения.

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

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

Возможно, поток завершен или что-то, когда вызывается renderBinary(). Я подозреваю, что то же самое происходит и для других вызовов render(), но я не проверял их.

Я решил проблему, переместив renderBinary() после try/catch. Дальнейшее исследование показало, что игра обеспечивает @Finally аннотацию для создания метода, который запускается после выполнения действия контроллера. Оговорка здесь в том, что это вызовет вызов после выполнения ЛЮБОГО действия в контроллере, поэтому он может не всегда быть хорошим выбором.

Ответ 10

В следующих случаях блок finally не будет выполнен: -

  • Когда System.exit(0) вызывается из блока try.
  • Когда JVM исчерпывает память
  • Когда ваш java-процесс принудительно убит из задачи mgr или консоли
  • Условие взаимоблокировки в блоке try
  • Когда ваш компьютер отключается из-за сбоя питания

Также могут быть и другие случаи, когда окончательный блок не будет выполнен.

Ответ 11

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