主动处理
runnable中通过try…catch进行处理
public void run() {
Throwable thrown = null;
try {
...
} catch (Throwable e) {
...
thrown = e
} finally {
// 线程退出的处理
threadExited(this, thrown);
}
}
通过UncaughtExceptionHandler处理
方法:
通过set方法设置异常处理器
Thread thread = new Thread();
thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
...
}
});
详解:
UncaughtExceptionHandler
UncaughtExceptionHandler为Thread的内部接口
@FunctionalInterface
public interface UncaughtExceptionHandler {
/**
* Method invoked when the given thread terminates due to the
* given uncaught exception.
* <p>Any exception thrown by this method will be ignored by the
* Java Virtual Machine.
* @param t the thread
* @param e the exception
*/
void uncaughtException(Thread t, Throwable e);
}
当一个线程由于未捕获异常而退出时,JVM会把这个事件报告给应用程序提供的UncaughtExceptionHandler 异常处理器。如果没有提供任何异常处理器,那么默认的行为是将栈追踪信息输出到System.err。(《Java并发编程实战》)
注释说到,该方法会被JVM调用,即上所说的报告给异常处理器
/**
* Dispatch an uncaught exception to the handler. This method is
* intended to be called only by the JVM.
*/
private void dispatchUncaughtException(Throwable e) {
getUncaughtExceptionHandler().uncaughtException(this, e);
}
追踪下uncaughtException的实现,如果没有设置异常处理器,则采用ThreadGroup group的方法,因此ThreadGroup中的为默认的异常处理方法
/* The group of this thread */
private ThreadGroup group;
// null unless explicitly set
private volatile UncaughtExceptionHandler uncaughtExceptionHandler;
...
public UncaughtExceptionHandler getUncaughtExceptionHandler() {
return uncaughtExceptionHandler != null ?
uncaughtExceptionHandler : group;
}
ThreadGroup
ThreadGroup的实现中可以看到,默认情况下的日志打印输出
public void uncaughtException(Thread t, Throwable e) {
if (parent != null) {
parent.uncaughtException(t, e);
} else {
Thread.UncaughtExceptionHandler ueh =
Thread.getDefaultUncaughtExceptionHandler();
if (ueh != null) {
ueh.uncaughtException(t, e);
} else if (!(e instanceof ThreadDeath)) {
System.err.print("Exception in thread \""
+ t.getName() + "\" ");
e.printStackTrace(System.err);
}
}
}
Thread中对ThreadGroup group的初始化
再来看下Thread中对ThreadGroup group的初始化:
- SecurityManager.getThreadGroup()获取ThreadGroup
- 如果为空,继续获取当前线程的ThreadGroup
而创建该对象的时候,当前线程即为父线程,因此这段代码可以理解为,如果SecurityManager中没有ThreadGroup,则获取父线程的ThreadGroup
P.S. SecurityManager的getThreadGroup也为获取当前线程的ThreadGroup,但是SecurityManager的子类不都是这种实现
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
...
Thread parent = currentThread();
SecurityManager security = System.getSecurityManager();
if (g == null) {
/* Determine if it's an applet or not */
/* If there is a security manager, ask the security manager
what to do. */
if (security != null) {
g = security.getThreadGroup();
}
/* If the security doesn't have a strong opinion of the matter
use the parent thread group. */
if (g == null) {
g = parent.getThreadGroup();
}
}
...
this.group = g;
}