问题
Thread.UncaughtExceptionHandler states that when the method which handles uncaught exceptions itself throws an exception, that exception will be ignored:
void uncaughtException(Thread t, Throwable e):
Method invoked when the given thread terminates due to the given uncaught exception.
Any exception thrown by this method will be ignored by the Java Virtual Machine.
However when I tested it, the JVM did not ignore the exceptions handled by the uncaught exception handler`:
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 Console output (JRE 1.7):
Exception: java.lang.RuntimeException thrown from the UncaughtExceptionHandler in thread "main"
Another oddity I found out is that the output I get isn't coming from System.err
. It seems to be from another stream altogether. I verified this by redirecting System.err
to System.out
, but I'm still getting "red" output:
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");
}
The output (bolded signifies red color):
true
this is black color
java.lang.Error: test stacktrace color at asf.df.main(df.java:13)
Exception: java.lang.RuntimeException thrown from the UncaughtExceptionHandler in thread "main"
What's the explanation for these phenomenons?
What happens to errors thrown within UncaughtExceptionHandler? What's the expected (documented or guaranteed) behavior?
回答1:
HotSpot JVM prints the exceptions thrown from the UncaughtExceptionHandler. See 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;
}
JVM prints these exceptions itself directly on stderr
regardless of the System.err
state - whether it was redirected or not.
Well, this kind of warning does not affect the application - in this sense the exception is "ignored". But you are right, this behavior is not obvious. Javadoc is misleading and is better to be fixed.
回答2:
The exceptions are ignored and processing continues when thrown from a non-main thread.
If it is thrown in main the error code returned is non-zero.
The unhandled exceptions are logged via 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");
}
Output:
In child UncaughtExceptionHandler at 2014-07-19T04:10:46.184Z
Exception: java.lang.RuntimeException thrown from the UncaughtExceptionHandler in thread "Thread-0" After child thread: 2014-07-19T04:10:48.197Z In main UncaughtExceptionHandler 2014-07-19T04:10:48.197Z
Exception: java.lang.RuntimeException thrown from the UncaughtExceptionHandler in thread "main"
来源:https://stackoverflow.com/questions/24834702/do-errors-thrown-within-uncaughtexceptionhandler-get-swallowed