programing

마지막으로 블록은 항상 실행됩니까?

newsource 2022. 9. 16. 21:05

마지막으로 블록은 항상 실행됩니까?

최종적으로 Java에서 실행되지 않는 조건이 있습니까?감사합니다.

Sun 튜토리얼에서

주의: Try 코드 또는 Catch 코드 실행 중에 JVM이 종료되면 최종적으로 블록이 실행되지 않을 수 있습니다.마찬가지로 try 또는 catch 코드를 실행하는 스레드가 중단되거나 중단되면 응용 프로그램 전체가 계속되더라도 최종 블록이 실행되지 않을 수 있습니다.

그 블록이 실행되지 않을 다른 방법은...

System.exit이 가상 시스템을 종료합니다.

현재 실행 중인 Java 가상 시스템을 종료합니다.인수는 상태 코드로 기능합니다.규칙상 0이 아닌 상태 코드는 비정상적인 종료를 나타냅니다.

는 " " 를 합니다.exit 내의 Runtime이 메서드는 정상적으로 반환되지 않습니다.

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

「bye」는, 상기의 코드로 인쇄되지 않습니다.

다른 사람의 의견을 자세히 설명하자면, JVM 종료와 같은 원인이 되지 않는 것은 모두 최종 블록이 됩니다.그래서 다음 방법이 있습니다.

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

이상하게도 컴파일과 반환 모두1이 됩니다

시스템 관련또한 최종 블록이 실행되지 않을 수 있는 특정 유형의 치명적인 장애도 있습니다.JVM의 메모리가 모두 부족하면 캐치 없이 종료되거나 최종적으로 종료될 수 있습니다.

구체적으로, 나는 우리가 어리석게 사용하려고 했던 프로젝트가 기억난다.

catch (OutOfMemoryError oome) {
    // do stuff
}

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

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

, 는되지 않은 「」가 한).Thread.stop툴 인터페이스를 통해 콜 또는 동등한 것을 호출합니다).

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

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

최종 블록을 자세히 살펴보면 "will not execute(실행하지 않을 수 있습니다)"라고 표시되지 않지만 "may not execute(실행하지 않을 수 있습니다)"라고 표시됩니다.다음은 올바른 설명입니다.

주의: Try 코드 또는 Catch 코드 실행 중에 JVM이 종료되면 최종적으로 블록이 실행되지 않을 수 있습니다.마찬가지로 try 또는 catch 코드를 실행하는 스레드가 중단되거나 중단되면 응용 프로그램 전체가 계속되더라도 최종 블록이 실행되지 않을 수 있습니다.

이 동작의 명백한 이유는 system.exit() 호출이 런타임시스템 스레드로 처리되기 때문에 jvm을 셧다운하는데 시간이 걸릴 수 있으며 스레드스케줄러는 최종적으로 실행을 요구할 수 있습니다.마지막으로 항상 실행되도록 설계되었지만, 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

인쇄되지 않습니다.

try 코드 또는 catch 코드가 실행되는 동안 JVM이 종료되면 최종적으로 블록이 실행되지 않을 수 있습니다.(소스)

Normal Shutdown - 마지막 비데몬 스레드가 종료되거나 Runtime.exit()(소스)가 종료될 때 발생합니다.

스레드가 종료되면 JVM은 실행 중인 스레드의 인벤토리를 수행하고 남은 스레드만 데몬 스레드일 경우 정상적인 셧다운을 시작합니다.JVM이 중지되면 나머지 데몬 스레드는 최종적으로 실행되지 않고 스택이 해제되지 않고 JVM이 종료됩니다.데몬 스레드는 몇 가지 처리 액티비티를 청소 없이 안전하게 폐기할 수 있는 경우가 거의 없습니다.특히 모든 종류의 I/O를 수행할 수 있는 작업에 데몬 스레드를 사용하는 것은 위험합니다.데몬 스레드는 메모리 내 캐시에서 만료된 항목을 주기적으로 제거하는 백그라운드 스레드 등 "하우스키핑" 작업에 가장 적합합니다.(소스)

데몬 이외의 마지막 스레드 종료 예:

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

다음과 같은 경우에는 최종적으로 블록이 실행되지 않습니다.

  • System.exit(0)됩니다.try
  • JVM의 메모리가 부족할 때
  • 태스크 매니저 또는 콘솔에서 Java 프로세스가 강제 종료된 경우
  • 「 」의 교착 상태try
  • 전원 장애로 인해 기계가 종료된 경우

또한 최종적으로 블록이 실행되지 않는 다른 프린지 케이스도 있을 수 있습니다.

최종적으로 블록 코드 실행을 중지하려면 다음 두 가지 방법이 있습니다.
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");  
        }
    }
  }
}

플레이 프레임워크와 관련하여 최종적으로 블록이 실행되지 않는 매우 구체적인 사례를 접했습니다.

이 컨트롤러 액션코드의 최종 블록이 호출된 것은 예외 이후뿐이며 콜이 실제로 성공했을 때는 호출되지 않는다는 것을 알고 놀랐습니다.

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

renderBinary()가 호출되었을 때 스레드가 종료되었을 수 있습니다.다른 render() 콜에서도 같은 일이 일어날 것으로 생각되지만 검증은 하지 않았습니다.

renderBinary()를 try/catch 후로 이동하여 문제를 해결했습니다.추가 조사 결과 play는 컨트롤러 액션이 실행된 후 실행되는 메서드를 작성하기 위한 @Finally 주석을 제공하는 것으로 나타났습니다.여기서 주의할 점은 컨트롤러에서 임의의 액션이 실행된 후에 호출되기 때문에 항상 적절한 선택은 아니라는 것입니다.

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

언급URL : https://stackoverflow.com/questions/464098/does-a-finally-block-always-run