Java에서 System.exit를 언제 호출해야합니까


193

Java System.exit(0)에서 다음 코드 와의 차이점은 무엇입니까 ?

public class TestExit
{      
    public static void main(String[] args)
    { 
        System.out.println("hello world");

        System.exit(0);  // is it necessary? And when it must be called? 
    }      
}

문서는 말한다 : "이 방법은 일반적으로 반환하지 않습니다." 무슨 뜻인가요?

답변:


207

System.exit()프로그램이 종료되기 전에 종료 후크 를 실행하는 데 사용할 수 있습니다 . 이는 프로그램의 모든 부분이 서로를 인식 할 수없고 인식해서는 안되는 더 큰 프로그램에서 종료를 처리하는 편리한 방법입니다. 그런 다음 누군가 종료하려면 간단히 전화를 걸 수 있으며 System.exit()종료 후크 (올바르게 설정된 경우)는 파일 닫기, 리소스 해제 등 필요한 모든 종료 행사를 처리합니다.

"이 방법은 정상적으로 반환되지 않습니다." 메서드가 반환되지 않음을 의미합니다. 실이 거기에 가면 다시 돌아 오지 않습니다.

프로그램을 종료하는 또 다른 더 일반적인 방법은 단순히 main방법 의 끝에 도달하는 것입니다 . 그러나 데몬 이외의 스레드가 실행중인 경우 종료되지 않으므로 JVM이 종료되지 않습니다. 따라서 데몬 이외의 스레드가있는 경우 데몬 이외의 스레드를 모두 종료하고 다른 자원을 해제하려면 다른 방법 (종료 후크보다)이 필요합니다. 데몬 이외의 다른 스레드가없는 경우에서 복귀 main하면 JVM이 종료되고 종료 후크가 호출됩니다.

어떤 이유로 든 셧다운 훅은 과소 평가되고 오해를 불러 일으키는 메커니즘으로 보이며 사람들은 프로그램을 종료하기 위해 모든 종류의 전용 사용자 지정 해킹으로 휠을 재발 명하고 있습니다. 종료 후크를 사용하는 것이 좋습니다. 어쨌든 사용할 표준 런타임 에는 모두 있습니다 .


10
"이 방법은 정상적으로 반환되지 않습니다." 메서드가 반환되지 않음을 의미합니다. 실이 거기에 가면 다시 돌아 오지 않습니다. 특히 이것은 System.exit (0) 호출을 만드는 메소드를 단위 테스트 할 수 없음을 의미합니다.
Bill Michell

5
-1 잘못되었습니다. JVM이 정상적으로 종료되면 System.exit 또는 main () 종료로 인해 종료 훅이 실행됩니다. 참조 ZX81 / 도쿠 / 자바 / 자바 독 / j2se1.5.0 / 문서 / API / 자바 / 랭 / ...
sleske

31
@sleske : 데몬이 아닌 다른 스레드가 있으면 main ()을 종료하는 것으로 충분하지 않습니다. System.exit ()를 명시 적으로 호출하지 않는 한 마지막 비 데몬 스레드가 종료 된 후에 만 ​​종료가 시작됩니다. 런타임 설명서에 명확하게 나와 있습니다.
Joonas Pulakka

3
종료 후크가 System.exit라는 스레드에 의존하는 경우 교착 상태가 발생합니다.
djechlin

8
추가해야 할 사항, 누군가가 런타임을 중단하면 종료 후크가 실행되지 않습니다 ( Runtime.getRuntime().halt())
Rogue

50

이 경우에는 필요하지 않습니다. 추가 스레드가 시작되지 않았으므로 종료 코드 (기본값 0)를 변경하지 않습니다. 기본적으로 의미가 없습니다.

문서에서 메소드가 정상적으로 반환되지 않는다고 말하면 컴파일러가 알지 못하더라도 후속 코드 행에 효과적으로 도달 할 수 없음을 의미합니다 .

System.exit(0);
System.out.println("This line will never be reached");

예외가 발생하거나 리턴하기 전에 VM이 종료됩니다. "반환"하지 않습니다.

System.exit()IME를 호출 할 가치가있는 경우는 매우 드 rare니다 . 명령 행 도구를 작성하는 경우 이치에 맞을 수 있으며 예외를 던지기보다는 종료 코드를 통해 오류를 표시하려고합니다. .


2
컴파일러는 왜 그것을 알지 못합니까? 특정 탐지 코드를 보증하기에 System.exit ()가 특별하지 않습니까?
바트 반 Heukelom

3
@Bart : 아니요, 그렇게 생각하지 않습니다. 이와 같은 것들을 위해 언어에 특별한 경우를 넣으면 별다른 이점없이 언어가 복잡해집니다.
Jon Skeet

나는 "정상적으로 복귀하지 않는다"는 진술의 "급격한 완료"와 관련이 있다고 생각했다. (JLS 섹션 14.1). 내가 잘못?
aioobe

@ aioobe : 아뇨, 당신 말이 맞아요. System.exit()항상 정상적으로 완료되지는 않습니다. 항상 예외 또는 VM 종료 (JLS에서는 실제로 다루지 않음)로 완료됩니다.
Jon Skeet

1
@piechuckerr : 어떻게 생각하세요? 프로그램에 오류가 발생했음을 호출 쉘 (또는 기타)에 표시하기 위해 0 이외의 값으로 호출하는 것이 전적으로 합리적입니다.
Jon Skeet

15

System.exit(0)JVM을 종료합니다. 이와 같은 간단한 예에서는 차이를 인식하기가 어렵습니다. 이 매개 변수는 OS로 다시 전달되며 일반적으로 비정상 종료 (예 : 치명적인 오류)를 나타내는 데 사용되므로 배치 파일 또는 쉘 스크립트에서 java를 호출 한 경우이 값을 가져 와서 아이디어를 얻을 수 있습니다. 응용 프로그램이 성공한 경우.

System.exit(0)응용 프로그램 서버에 배포 된 응용 프로그램 을 호출 한 경우 상당한 영향을 미칩니다 (사용하기 전에 생각하십시오).


15

이 메소드는 세계의 끝이므로 절대로 리턴하지 않으며 다음 코드는 실행되지 않습니다.

예제에서 응용 프로그램은 코드의 동일한 지점에서 종료되지만 System.exit을 사용하는 경우 종료됩니다. 사용자 정의 코드를 환경에 반환하는 옵션이 있습니다.

System.exit(42);

누가 종료 코드를 사용합니까? 응용 프로그램을 호출 한 스크립트 Windows, Unix 및 기타 모든 스크립트 가능한 환경에서 작동합니다.

왜 코드를 반환합니까? "성공하지 못했습니다", "데이터베이스가 응답하지 않았습니다"와 같은 것을 말하십시오.

종료 코드를 od 코드로 가져 와서 유닉스 쉘 스크립트 나 Windows cmd 스크립트에서 사용하는 방법을 보려면 이 사이트에서이 답변을 확인 하십시오


12

복잡한 종료 후크가있는 응용 프로그램에서는 알 수없는 스레드에서이 메서드를 호출하면 안됩니다. System.exitJVM이 종료 될 때까지 호출이 차단되므로 정상적으로 종료되지 않습니다. 마치 마치 실행하기 전에 전원 플러그를 뽑은 코드가 실행중인 것처럼 보입니다. 호출 System.exit하면 프로그램의 종료 후크와 System.exit프로그램 종료까지 호출하는 스레드가 시작 됩니다. 이는 종료 후크가 차례로 System.exit호출 된 스레드에 태스크를 제출 하면 프로그램이 교착 상태가된다는 의미입니다.

내 코드에서 다음을 처리하고 있습니다.

public static void exit(final int status) {
    new Thread("App-exit") {
        @Override
        public void run() {
            System.exit(status);
        }
    }.start();
}

또한 System.exit가 실제로 JVM을 종료하지 않는 문제가있었습니다. 그러나 특정 조건에서만 발생했습니다. 내가 찍은 threadump는 어떤 스레드 / 종료 처리기가 종료를 차단하는지에 대한 통찰력을주지 못했습니다. 주석에 설명 된 코드를 사용하면 문제를 해결하는 데 도움이되었습니다!
Kai

7

답변이 실제로 도움이되었지만 더 자세한 내용을 놓친 방법이 있습니다. 위의 답변 외에도 아래의 Java 종료 프로세스를 이해하는 데 도움이되기를 바랍니다.

  1. 순차적 * 종료에서 JVM은 먼저 등록 된 모든 종료 후크를 시작합니다. 종료 후크는 Runtime.addShutdownHook에 등록 된 시작되지 않은 스레드입니다.
  2. JVM은 종료 후크가 시작되는 순서를 보장하지 않습니다. 종료시 응용 프로그램 스레드 (데몬 또는 비 데몬)가 여전히 실행중인 경우 종료 프로세스와 동시에 계속 실행됩니다 .
  3. 모든 종료 후크가 완료되면 runFinalizersOnExit가 true 인 경우 JVM이 종료자를 실행하도록 선택한 다음 중지됩니다.
  4. JVM은 종료시 여전히 실행중인 응용 프로그램 스레드를 중지하거나 중단하지 않습니다. JVM이 결국 정지되면 갑자기 종료됩니다.
  5. 종료 후크 또는 종료자가 완료되지 않으면 순서대로 종료 프로세스가 중단되고 JVM을 갑자기 종료해야합니다.
  6. 갑작스런 종료에서 JVM은 JVM을 중지하는 것 외에 다른 작업을 수행 할 필요가 없습니다. 종료 후크가 실행되지 않습니다.

PS : JVM은 순서대로 또는 갑작스럽게 종료 될 수 있습니다 .

  1. 마지막 "정상"(nondaemon) 스레드가 종료되거나 누군가 System.exit를 호출하거나 다른 플랫폼 별 수단 (예 : SIGINT 전송 또는 Ctrl-C 치기)에 의해 순차적으로 종료됩니다.
  2. 위의 방법은 JVM을 종료하는 표준적이고 선호되는 방법이지만 Runtime.halt를 호출하거나 운영 체제를 통해 JVM 프로세스를 종료 (예 : SIGKILL 전송)하여 갑자기 종료 할 수도 있습니다.

7

System.exit(0)다음과 같은 이유로 전화해서는 안됩니다 .

  1. 숨겨진 "goto"와 "gotos"는 제어 흐름을 깨뜨립니다. 이 맥락에서 후크에 의존하는 것은 팀의 모든 개발자가 알고 있어야하는 정신적 매핑입니다.
  2. 프로그램을 "정상적으로"종료하면 운영 체제에 동일한 종료 코드가 제공 System.exit(0)되므로 중복됩니다.

    프로그램이 "정상적으로"종료되지 않으면 개발에 대한 통제력을 상실한 것입니다 [디자인]. 항상 시스템 상태를 완전히 제어해야합니다.

  3. 정상적으로 중지되지 않은 스레드 실행과 같은 프로그래밍 문제는 숨겨집니다.
  4. 스레드를 비정상적으로 중단하는 응용 프로그램 상태가 일치하지 않을 수 있습니다. (# 3 참조)

그건 그렇고 : 비정상적인 프로그램 종료를 나타내려면 0 이외의 다른 반환 코드를 반환하는 것이 좋습니다.


2
"시스템 상태를 항상 완전히 제어해야합니다." Java에서는 불가능합니다. IoC 프레임 워크 및 애플리케이션 서버는 시스템 상태 제어를 포기하는 매우 인기 있고 널리 사용되는 두 가지 방법입니다. 그리고 그것은 완전히 괜찮습니다.
mhlz

응용 프로그램 서버에서 System.exit (0)을 실행하고 서버 관리자의 반응에 대해 알려주십시오.이 질문의 주제와 내 답변을 놓쳤습니다.
oopexpert

어쩌면 나는 충분히 명확하지 않았다. 항상 담당하는 시스템 상태를 완전히 제어해야합니다. 예, 일부 책임은 애플리케이션 서버와 IoC로 옮겨졌습니다. 그러나 나는 그것에 대해 이야기하지 않았습니다.
oopexpert

5

System.exit가 필요합니다

  • 0이 아닌 오류 코드를 반환하려는 경우
  • main ()이 아닌 곳에서 프로그램을 종료하고 싶을 때

귀하의 경우, 간단한 메인 리턴과 동일한 기능을 수행합니다.


후자는 무엇을 의미합니까? 프로그램을 종료하는 올바른 방법은 모든 스레드를 중지시키는 것입니다 (주로), 메인 스레드에서 시작할 필요가없는 이동이므로, exit유일한 옵션은 아닙니다.
바트 반 Heukelom

@Bart : 당신이 설명하는 것은 올바른 방법이 아니라 프로그램을 종료 하는 가능한 방법 중 하나입니다 . 종료 후크를 사용하여 모든 스레드를 멋지게 중지하는 데 아무런 문제가 없습니다. 으로 종료 후크가 시작됩니다 . 유일한 옵션은 아니지만 고려해야 할 옵션입니다. exit
Joonas Pulakka

그러나 문서에서 수집 한 것, 종료 후크는 매우 섬세하며 원하는 작업을 수행하는 데 많은 시간이 없을 수 있습니다. 꼭, OS 종료 또는 무언가의 경우 잘 종료하려면 사용하십시오. 그러나 System.exit () 직접 호출하려는 경우 종료 코드를 수행하는 것이 좋습니다. 더 이상 System.exit () 필요)
Bart van Heukelom

1
셧다운 후크는 완료하는 데 항상 시간이 걸립니다. 모든 후크가 리턴되기 전에 VM이 정지되지 않습니다. 실행하는 데 시간이 오래 걸리는 종료 후크를 등록하여 VM이 종료되는 것을 방지 할 수 있습니다. 그러나 물론 다양한 대체 방법으로 종료 시퀀스를 수행 할 수 있습니다.
Joonas Pulakka

데몬 이외의 다른 스레드가있는 경우 main에서 복귀해도 종료되지 않습니다.
djechlin

4

자바 언어 사양에 따르면

프로그램 종료

프로그램은 모든 활동을 종료하고 다음 두 가지 중 하나가 발생하면 종료됩니다.

데몬 스레드가 아닌 모든 스레드가 종료됩니다.

일부 스레드는 Runtime 클래스 또는 System 클래스의 exit 메소드를 호출하며 , 보안 관리자는 종료 조작을 금지하지 않습니다.

즉, 큰 프로그램 (이보다 크지 않은)이 있고 실행을 끝내고 싶을 때 사용해야합니다.


3

JVM에서 다른 프로그램을 실행 중이고 System.exit를 사용하는 경우 해당 두 번째 프로그램도 닫힙니다. 예를 들어 클러스터 노드에서 Java 작업을 실행하고 클러스터 노드를 관리하는 Java 프로그램이 동일한 JVM에서 실행된다고 가정하십시오. 작업이 System.exit를 사용하는 경우 작업을 종료 할뿐만 아니라 "완전한 노드를 종료"합니다. 관리 프로그램이 실수로 닫혀서 다른 작업을 해당 클러스터 노드로 보낼 수 없습니다.

따라서 동일한 JVM 내의 다른 Java 프로그램에서 프로그램을 제어하려면 System.exit를 사용하지 마십시오.

의도적으로 전체 JVM을 닫고 다른 응답에 설명 된 가능성을 활용하려면 System.exit를 사용하십시오 (예 : 종료 후크 : Java 종료 후크 , 명령 행의 0이 아닌 리턴 값) 호출 : Windows 배치 파일에서 Java 프로그램의 종료 상태를 얻는 방법 ).

또한 런타임 예외를 살펴보십시오 : System.exit (num) 또는 main에서 RuntimeException을 던지십니까?

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.