마침내 자바에서 실행되지 않는 조건이 있습니까? 감사.
마침내 자바에서 실행되지 않는 조건이 있습니까? 감사.
답변:
로부터 일 자습서
참고 : 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
이 호출되거나 도구 인터페이스를 통해 이와 동등한 항목이 호출 되지 않는 한 ).
throw
, 다음 finally
예상대로 블록이 실행됩니다. try { throw new ThreadDeath(); } finally { System.err.println("?"); }
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
"마지막으로"는 인쇄되지 않습니다.
try 또는 catch 코드가 실행되는 동안 JVM이 종료되면 finally 블록이 실행되지 않을 수 있습니다. ( 출처 )
정상 종료-마지막 비 데몬 스레드가 종료되거나 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
다음과 같은 경우 finally 블록은 실행되지 않습니다.
System.exit(0)
에서 호출try
블록. try
블록의 finally 블록이 실행되지 않는 다른 프린지 케이스도있을 수 있습니다.
finally 블록 코드 실행을 중지하는 방법에는 두 가지가 있습니다.
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");
}
}
}
}
나는 play 프레임 워크와 관련하여 실행되지 않는 finally 블록의 매우 구체적인 경우를 보았습니다.
이 컨트롤러 액션 코드의 finally 블록은 Exception 이후에만 호출되었지만 실제로 호출이 성공했을 때는 호출되지 않았다는 사실에 놀랐습니다.
try {
InputStream is = getInputStreamMethod();
renderBinary(is, "out.zip");
catch (Exception e) {
e.printStackTrace();
} finally {
cleanUp();
}
스레드가 종료되거나 renderBinary ()가 호출 될 때 무언가가 종료 될 수 있습니다. 다른 render () 호출에서도 같은 일이 발생한다고 생각하지만 확인하지는 않았습니다.
try / catch 이후로 renderBinary ()를 이동하여 문제를 해결했습니다. 추가 조사에 따르면 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");
}
}