[java] finally 블록은 항상 실행됩니까?

마침내 자바에서 실행되지 않는 조건이 있습니까? 감사.



답변

로부터 일 자습서

참고 : try 또는 catch 코드가 실행되는 동안 JVM이 종료되면 finally 블록이 실행되지 않을 수 있습니다. 마찬가지로 try 또는 catch 코드를 실행하는 스레드가 중단되거나 종료되면 응용 프로그램 전체가 계속 되더라도 finally 블록이 실행되지 않을 수 있습니다.

나는 finally 블록이 실행되지 않는 다른 방법을 모릅니다.


답변

System.exit 는 가상 머신을 종료합니다.

현재 실행중인 Java Virtual Machine을 종료합니다. 인수는 상태 코드 역할을합니다. 일반적으로 0이 아닌 상태 코드는 비정상 종료를 나타냅니다.

이 메서드는 exit클래스 의 메서드를 호출합니다 Runtime. 이 메서드는 정상적으로 반환되지 않습니다.

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

“bye”는 위의 코드에서 인쇄되지 않습니다.


답변

다른 사람들의 말을 확장하기 위해 JVM 종료와 같은 것을 유발하지 않는 것은 finally 블록을 발생시킵니다. 따라서 다음 방법 :

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

이상하게도 컴파일하고 1을 반환합니다.


답변

System.exit와 관련하여 finally 블록이 실행되지 않는 특정 유형의 치명적인 오류도 있습니다. JVM에 메모리가 완전히 부족하면 catch 또는 최종적으로 발생하지 않고 종료 될 수 있습니다.

특히 우리가 어리석게 사용하려고 한 프로젝트가 기억납니다.

catch (OutOfMemoryError oome) {
    // do stuff
}

JVM에는 catch 블록을 실행하기위한 메모리가 남아 있지 않기 때문에 작동하지 않았습니다.


답변

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

이 경우 finally는 실행되지 않습니다 (비추천 항목 Thread.stop이 호출되거나 도구 인터페이스를 통해 이와 동등한 항목이 호출 되지 않는 한 ).


답변

Sun 튜토리얼은이 스레드에서 잘못 인용되었습니다.

참고 : try 또는 catch 코드가 실행되는 동안 JVM이 종료되면 finally 블록 실행되지 않습니다. 마찬가지로 try 또는 catch 코드를 실행하는 스레드가 중단되거나 종료 되면 응용 프로그램이 전체적으로 계속 되더라도 finally 블록 실행되지 않습니다.

finally 블록에 대한 sun 자습서를 자세히 살펴보면 “실행하지 않을 것”이 아니라 “실행할 수 없음”이 표시됩니다. 올바른 설명은 다음과 같습니다.

참고 : try 또는 catch 코드가 실행되는 동안 JVM이 종료되면 finally 블록 실행되지 않을 수 있습니다. 마찬가지로 try 또는 catch 코드를 실행하는 스레드가 중단되거나 종료 되면 응용 프로그램 전체가 계속 되더라도 finally 블록 실행되지 않을 수 있습니다 .

이 동작의 명백한 이유는 system.exit () 호출이 런타임 시스템 스레드에서 처리되어 jvm을 종료하는 데 시간이 걸릴 수 있지만 스레드 스케줄러가 마지막으로 실행을 요청할 수 있기 때문입니다. 그래서 finally는 항상 실행되도록 설계되었지만 jvm을 종료하는 경우 최종적으로 실행되기 전에 jvm이 종료 될 수 있습니다.


답변

또한 내부에서 교착 상태 / 라이브 락이 발생하는 경우 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

“마지막으로”는 인쇄되지 않습니다.