主動處理
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;
}