2014-05-20 1 views
1

이 질문은 Exception in finalize method 및 이와 유사한 질문과 반대입니다.finalize 메서드에서 사용자가 볼 수있는 예외를 트리거

제대로 닫히지 않으면 심각한 위험을 초래하는 AutoCloseable 클래스를 생성 중입니다. 나는 그런 경우에 실패하기를 바라고있어 사용자가 우연히 그렇게하는 것을 잊지 않도록한다.

Closeable 일반 우수 사례가 정상적으로 작동하지 않아 발신자의 오류를 완화하기 위해 최선을 다하고 있지만이 경우 발신자가이 기능을 놓치지 않을 것임을 알고 있습니다. 아이디어에 개념적으로 동의하지 않는다면, 귀하의 의견에 감사 드리며,이 경우 자바 내부에 대한 학문적 인 질문을 생각해보십시오.

내가 상상 한 것은 IllegalStateException을 발생시키고 클래스의 finalize() 메서드가 호출되고 인스턴스가 아직 정리되지 않은 경우 사용자를 방해하는 것입니다. 그러나 finalize()은 명시 적으로 포착되지 않은 예외를 삼켜 버리기 때문에 까다로울 수 있습니다. 사용자가 finalize() 방법에서 볼 수있는 RuntimeException을 발생시키는 가장 좋은 방법은 무엇입니까? 내가 그 finalize() 실행이 보장되지도 실현, 그래서이 방법을 주위에 구현하는 것을 절대적으로 일어나지 않을 것입니다 :

public class SeriouslyCloseable implements AutoCloseable { 
    // We construct an Exception when the class is initialized, so that the stack 
    // trace informs where the class was created, rather than where it is finalized 
    private final IllegalStateException leftUnclosed = new IllegalStateException(
     "SEVERE: "+getClass().getName()+" was not properly closed after use"); 
    private boolean safelyClosed = false; 

    @Override 
    public void close() { 
    // do work 
    safelyClosed = true; 
    } 

    @Override 
    protected void finalize() throws IllegalStateException { 
    if(!safelyClosed) { 
     // This is suppressed by the GC 
     throw leftUnclosed; 
    } 
    } 
} 

참고 : 여기에

는 내가 지금까지 뭘 찾았는지의 데모 클래스의 . 나는 GC가 우리에게 기회를 준다면 여전히 으로, 아마도이 일어나기를 원할 것이다.

답변

1

는이 방법이 Thread 따라 임의의 구현에 의해 실행하고 예외를 인상해야하는 Thread에서 분명하지 않다함에 따라 finalize 방법에서 예외를 던지는 강제 할 수 없다. 스레드를 유발하는 많은 원인이 할 수있는 임의의 코드 위치에서 임의의 throw 가능 객체를 던져 : 당신이 목표로하는 스레드의 생각을했다하더라도

Thread.stop(Throwable)는 (자바 8부터 지원되지 않는)는 지원되지 않습니다 왜 좋은 이유가 해로움의. 예 : 스레드가 들어갈 다른 close() 작업을 놓치십시오. 또한 finalize 메서드가 호출 될 때 실수를 만드는 스레드가 더 이상 작동하지 않을 수 있습니다. 이 던지는에 대해 아니에요 결국


하지만 당신이 달성하고자하는 예외을보고. 다음과 같이 원래의 비 억압 동작을 모방 할 수 있습니다.

@Override 
protected void finalize() throws Throwable { 
    if(!safelyClosed) { 
     final Thread t = Thread.currentThread(); 
     t.getUncaughtExceptionHandler().uncaughtException(t, leftUnclosed); 
    } 
} 

기본적으로 예외 스택 추적이 콘솔에 인쇄됩니다. printStackTrace을 수동으로 호출하는 것보다 이점은 설치된 응용 프로그램 관련 예외 처리기와 함께 작동한다는 것입니다.

import java.util.logging.Level; 
import java.util.logging.Logger; 

public class ThrowableInFinalize { 
    public static void main(String[] args) throws InterruptedException { 
    Thread.setDefaultUncaughtExceptionHandler(
              new Thread.UncaughtExceptionHandler() { 
     public void uncaughtException(Thread t, Throwable e) { 
     Logger.getLogger("ThrowableInFinalize") 
       .log(Level.SEVERE, "uncaught exception", e); 
     } 
    }); 
    new ThrowableInFinalize(); 
    System.gc(); 
    Thread.sleep(1000); 
    } 

    private final IllegalStateException leftUnclosed = new IllegalStateException(
     "SEVERE: "+getClass().getName()+" was not properly closed after use"); 
    private boolean safelyClosed; 
    @Override 
    protected void finalize() throws Throwable { 
    if(!safelyClosed) { 
     final Thread t = Thread.currentThread(); 
     t.getUncaughtExceptionHandler().uncaughtException(t, leftUnclosed); 
    } 
    } 
} 
1

하나의 옵션은 단순히 철처 JVM을 종료하는 것입니다 :

private static void resourceLeak() { 
    SeriouslyCloseable sc = new SeriouslyCloseable(); 
    //sc.close(); 
} 

public static void main(String[] args) throws InterruptedException { 
    resourceLeak(); 
    System.gc(); 
    Thread.sleep(1000); 
    System.out.println("Exiting Normally"); 
} 
다음

@Override 
protected void finalize() throws IllegalStateException { 
    if(!safelyClosed) { 
    leftUnclosed.printStackTrace(System.err); 
    System.exit(255); 
    } 
} 

꽤 지속적으로 닫히지 않은 Closeable가 생성 된 곳의 흔적을 보여주는 포함, 원하는 동작을 복제

java.lang.IllegalStateException: SEVERE: SeriouslyCloseable was not properly closed after use 
     at SeriouslyCloseable.<init>(SeriouslyCloseable.java:5) 
     at SeriouslyCloseable.method(SeriouslyCloseable.java:23) 
     at SeriouslyCloseable.main(SeriouslyCloseable.java:28) 
0

finalize에서 예외를 throw하지 마십시오. .

그럼 심각한 프로그래밍 오류가 발생하여 어떻게 comunicate 할 수 있습니까? 너는 그것을 기록 할 수 있었다. 그러나 누군가가 그 로그를 읽을 때만 유용합니다.

당신은 전체 응용 프로그램을 사용할 수 없게 (또는 적어도 라이브러리) 만들 것 몇 가지 플래그 플립 수 - 정적 필드의 예외 (원래 널)과이 설정이 경우 몇 가지 동작을 던져에 저장합니다. JVM을 종료해도 문제가 발생하지 않으면 파일에 기록 할 수 있지만 때로는 시작할 수 없습니다. 시작 및 다시 시작 (파일이 삭제되고 응용 프로그램이 다시 시작될 때까지) 할 때로드 할 수 있습니다.

당신은 종료 (dimo414 내 앞에 제안) JVM하지만, 같은 애플리케이션 서버의 다른 응용 프로그램은 당신을 감사하지 않을 수 있습니다, 그리고 다른 자원을 닫는 방지합니다.

당신은 다른 곳 (예. HTTP 또는 JMS를 통해) 어떤 메시지를 보낼 수 있지만, 듣기와 로그 이하 무시할 수 어딘가에 필요합니다.

그리고 여러 가지 옵션을 구현하여이를 처리하고 사용자가 선택할 수있게 할 수 있습니다.

관련 문제