線程異常的處理

主動處理

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的初始化:

  1. SecurityManager.getThreadGroup()獲取ThreadGroup
  2. 如果爲空,繼續獲取當前線程的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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章