9

Thread.UncaughtExceptionHandler声明当处理未捕获异常的方法本身抛出异常时,该异常将被忽略:

void uncaughtException(线程 t,可抛出 e):

当给定线程由于给定的未捕获异常而终止时调用的方法。

Java 虚拟机将忽略此方法引发的任何异常。

但是,当我测试它时,JVM 并没有忽略未捕获的异常处理程序处理的异常:

public static void main(final String args[]) {
    Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
        @Override
        public void uncaughtException(Thread arg0, Throwable arg1) {
            throw new java.lang.RuntimeException("e2");
        }
    });
    throw new RuntimeException("e1");
}

Eclipse 控制台输出(JRE 1.7):

异常:从线程“main”中的 UncaughtExceptionHandler 抛出 java.lang.RuntimeException

我发现的另一个奇怪之处是我得到的输出不是来自System.err. 它似乎完全来自另一个流。我通过重定向验证了这一点System.errSystem.out但我仍然得到“红色”输出:

public static void main(final String[] args) {
    System.setErr(System.out);
    System.out.println(System.err == System.out);
    System.err.println("this is black color");
    try {
        throw new Error("test stacktrace color");
    } catch (Throwable e) {
        e.printStackTrace();
    }
    try {
        Thread.sleep(2500);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
        @Override
        public void uncaughtException(Thread t, Throwable e) {
            throw new RuntimeException("from handler");
        }
    });
    throw new RuntimeException("from main");
}

输出(粗体表示红色):

真的

这是黑色

java.lang.Error:在 asf.df.main(df.java:13) 测试堆栈跟踪颜色

异常:从线程“main”中的 UncaughtExceptionHandler 抛出 java.lang.RuntimeException

这些现象的解释是什么?

UncaughtExceptionHandler 中抛出的错误会发生什么?预期(记录或保证)的行为是什么?

4

2 回答 2

5

HotSpot JVM 打印从 UncaughtExceptionHandler 抛出的异常。请参阅JavaThread::exit

    if (HAS_PENDING_EXCEPTION) {
      ResourceMark rm(this);
      jio_fprintf(defaultStream::error_stream(),
            "\nException: %s thrown from the UncaughtExceptionHandler"
            " in thread \"%s\"\n",
            pending_exception()->klass()->external_name(),
            get_thread_name());
      CLEAR_PENDING_EXCEPTION;
    }

stderr无论状态如何, JVM 都会直接打印这些异常System.err——无论它是否被重定向。

好吧,这种警告不会影响应用程序——从这个意义上说,异常被“忽略”了。但你是对的,这种行为并不明显。Javadoc 具有误导性,最好修复。

于 2014-07-19T22:47:04.757 回答
2

当从非主线程抛出时,异常将被忽略并继续处理。

如果它在 main 中抛出,则返回的错误代码非零。

通过 syserr 记录未处理的异常。

public static void main(final String[] args) {

    final Thread myThread = new Thread(new Runnable() {

        @Override
        public void run() {
            Thread.currentThread()
                .setUncaughtExceptionHandler(new UncaughtExceptionHandler() {

                    @Override
                    public void uncaughtException(final Thread t, final Throwable e) {

                        System.out.println("In child UncaughtExceptionHandler at " + java.time.Instant.now());

                        throw new RuntimeException("From child thread UncaughtExceptionHandler"
                                + java.time.Instant.now());

                    }
                });
            throw new RuntimeException("from runnable");
        }
    });

    Thread.currentThread()
    .setUncaughtExceptionHandler(new UncaughtExceptionHandler() {

        @Override
        public void uncaughtException(final Thread t, final Throwable e) {

                System.out.println("In main UncaughtExceptionHandler " + java.time.Instant.now());

                throw new RuntimeException("From main thread UncaughtExceptionHandler" + java.time.Instant.now());

        }
    });

    myThread.start();

    LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(2));

    System.out.println("After child thread: " + java.time.Instant.now());

    //Will result in a non-zero return code
    throw new RuntimeException("from main");
}

输出:

在 2014-07-19T04:10:46.184Z 的子 UncaughtExceptionHandler

异常:从线程“Thread-0”中的 UncaughtExceptionHandler 抛出 java.lang.RuntimeException 在子线程之后:2014-07-19T04:10:48.197Z 在主 UncaughtExceptionHandler 2014-07-19T04:10:48.197Z

异常:从线程“main”中的 UncaughtExceptionHandler 抛出 java.lang.RuntimeException

于 2014-07-19T04:12:35.307 回答