IT_Programming/Java

Handling Uncaught Exeptions

JJun ™ 2010. 11. 30. 13:45

-------------------------------------------------------------------------------------------------

 출처: http://akira74.namoweb.net/bbs/view.php?id=java&page=1&sn1=&divpage=1&sn=off&ss=on&sc=on&keyword=64&select_arrange=headnum&desc=asc&no=107

-------------------------------------------------------------------------------------------------

 

 

2002 년 06 월 24 일
By   Glen McCluskey

Java 프로그래밍 언어로 프로그래밍을 많이 해 보았다면 처리되지 않은 예외가 발생해 애플리케이션이

비정상적으로 종료되는 경험을 해 본 적이 있을 것이다. 아래의 프로그램이 바로 그런 예이다 :

public class ExcDemo1 {
    public static void main(String args[]) {
      int vec[] = new int[10];
      vec[10] = 37;
    }
  }

이 예에서는 처리되지 않은 예외가 발생해서 프로그램이 비정상적으로 종료된다.

이 프로그램은 vec[10]으로의 illegal array 액세스 때문에 예외를 발생시킨다.

(vec 은 0부터 9까지의 유효한 array 인덱스를 가진다).

처리되지 않은 예외를 처리하기 위한 몇몇 기법들을 검토하기 전에 Java Virtual Machine이 프로그램을

종료시키는 규칙들에 대해 먼저 살펴보자. 첫번째 규칙은 처리되지 않은 예외가 자신이 발생한 스레드를

종료시키는 것이다. 두번째는 더 이상 사용가능한 유저 스레드가 존재하지 않을 때 프로그램이 종료된다.

 

아래의 예를 보자 :


class MyThread extends Thread {
    public void run() {
        try {
          Thread.sleep(5 * 1000);
        }
        catch (InterruptedException e) {
          System.err.println(e);
      }
    
      System.out.println("MyThread thread still alive");
    }
  }
    
  public class ExcDemo2 {
    public static void main(String args[]) {
      new MyThread().start();
    
      int vec[] = new int[10];
      vec[10] = 37;
    }
  }

메인 스레드가 처리되지 않은 예외 때문에 거의 곧바로 종료된다.

그러나 MyThread의 인스턴스가 약 5초간 동안 활동하는 상태로 지속되며 정상적으로 완료된다.
그렇다면 처리되지 않은 예외를 어떻게 처리할 것인가? 첫번째 방식은 매우 간단하다 -try..catch 블록으로

애플리케이션을 호출하는 제일 높은 수준의 메서드를 싸는 것이다.


public class ExcDemo3 {
    static void app() {
      int vec[] = new int[10];
      vec[10] = 37;
    }
    
    public static void main(String args[]) {
      try {
        app();
      }
      catch (Exception e) {
        System.err.println("uncaught exception: " + e);
      }
    }
  }

애플리케이션이 일반적으로 처리(catch)하려고 하는 모든 예외들은 java.lang.Exception의 서브클래스들이기 때문에 이 기법을 사용하면 처리할 수 있다. 하지만 OutOfMemoryException의 이 방법에서 제외되는데, 왜냐하면 이 예외는 java.lang.Error의 서브클래스이기 때문이다. 정말로 모든 것을 다 처리하고 싶다면 (꼭 좋은 생각은 아니지만), "catch (Throwable e)" 절을 사용할 수도 있다.


이 기법을 확장해서 복수의 스레드가 실행되는 환경에서 사용하고 싶다면 어떻게 해야 하는가?

당연한 접근 방식은 아래와 같다 :


class MyThread extends Thread {
    public void run() {
      int vec[] = new int[10];
      vec[10] = 37;
    }
  }
    
  public class ExcDemo4 {
    public static void main(String args[]) {
      try {
        new MyThread().start();
      }
      catch (Exception e) {
        System.err.println("uncaught exception: " + e);
      }
    }
  }

불행히도 이 방식으로는 원하는 바를 얻을 수 없다.

- 시작되는 메서드 자체가 발생시키는 예외 - IllegalThreadStartException 스레드가 이미 시작되었을 때

발생함 - 만을 처리할 뿐이다. 그러므로 좀 더 정교한 방법을 취해서 ThreadGroup 클래스의 uncaughtException 메서드를 오버라이드한다. ThreadGroup 객체는 스레드의 그룹을 나타낸다. ThreadGroup 내에는 한가지 메서드가 있는데, 이 메서드는 이 그룹내의 스레드가 처리되지 않은 예외가

발생해서 사라질(die) 때가 되면 호출된다.

아래는 이 메서드의 코드이다 :


class MyThreadGroup extends ThreadGroup {
    public MyThreadGroup(String s) {
      super(s);
    }
    
    public void uncaughtException(Thread t, Throwable e) {
      System.err.println("uncaught exception: " + e);
      file://super.uncaughtException(t, e);
    }
  }
    
  class MyThread extends Thread {
    public MyThread(ThreadGroup tg, String n) {
      super(tg, n);
    }
    
    public void run() {
      int vec[] = new int[10];
      vec[10] = 37;
    }
  }
    
  public class ExcDemo5 {
    public static void main(String args[]) {
      ThreadGroup tg = new MyThreadGroup("mygroup");
      Thread t = new MyThread(tg, "mythread");
    
      t.start();
    }
  }

이 코드 예는 ThreadGroup의 서브클래스를 생성하고 uncaughtException 메서드를 오버라이드한다.

이 오버라이드된 메서드는 사라지는(dying) 스레드를 위해 호출된다.

이 스레드 객체와 예외가 그 메서드에 패러미터로 전달된다.

uncaughtException은 스레드 그룹의 parent 그룹 객체에서 uncaughtException 메서드를 호출한다.

그런 그룹이 존재하지 않으면 그 예외의 printStackTrace 메서드가 호출되어 stack trace를 출력한다.

 

"system.err.println" 줄에 주석을 달고 "super.uncaughtException(t, e)" 줄의 주석 처리를 지우면

이 디폴트 동작이 어떤 식으로 일어나는 지를 확인할 수 있다.

 

 



참고 자료 : Arnold, Gosling 및 Holmes의 "The Java Programming Language Third Edition" (http://java.sun.com/docs/books/javaprog/thirdedition/)의 섹션 10.12 Thread and exception과 섹션 18.3의 Shutdown.