在Thread中有異常處理器相關的方法
在ThreadGroup中也有相關的異常處理方法
示例
未檢查異常
對於未檢查異常,將會直接宕掉,主線程則繼續運行,程序會繼續運行
在主線程中能不能捕獲呢?
咱們簡單粗暴一點,直接所有包到try catch中
你會發現,然而並無什麼卵用,主線程中的try catch並不會獲得什麼信息,跟原來的結果仍是同樣的,線程直接宕掉
已檢查異常
對於已檢查的異常,run方法自己是不支持拋出的,上面代碼中,想要throws,IDE提示異常,從run方法能夠看得出來
run方法自己是不支持throws的(簽名中沒有throws)
因此怎麼辦?
既然是已檢查異常,確定是要處理的,既然不能丟出去,就只有一個辦法了,那就是本身捕獲,放置在try catch中
小結
在run方法中是不可以拋出異常的,若是是已檢查的異常,那麼必須進行try catch
對於未檢查的異常,若是沒有進行處理,一旦拋出線程將會宕掉,並且在主線程中並不能捕獲到這個異常
難道對於未檢查的異常也都是try catch嗎?(固然,這是一種方式)
還有沒有其餘解決方案?
異常處理器
在Java線程的run方法中,對於未檢查異常,藉助於異常處理器進行處理的
字面意思,直接理解爲處理異常的方法,那麼如何配置這個處理異常的方法呢?如何設置,又是如何調用?
UncaughtExceptionHandler,是Thread的內部接口(1.8中已經設置爲函數式接口)
Thread內部有兩個變量,用於記錄異常處理器
對於兩個set方法,沒有什麼特別的,主要就是設置這兩個內部變量
對於getUncaughtExceptionHandler方法,若是當前非空,那麼返回當前,不然,將返回當前線程組,很顯然,ThreadGroup實現了Thread.UncaughtExceptionHandler
對於getDefaultUncaughtExceptionHandler,這是簡單的返回內部變量
此時咱們大體瞭解到了這幾個方法,內部有兩個UncaughtExceptionHandler異常處理器,分別都有getter和setter方法
setter方法都是直接設置
getDefaultUncaughtExceptionHandler是直接獲取
getUncaughtExceptionHandler若是非空那麼直接獲取,不然將會返回當前線程組,當前線程組也實現了Thread.UncaughtExceptionHandler,內部實現了方法public void uncaughtException(Thread t, Throwable e)
換句話說,線程組內部實現了一個線程處理器
兩個處理器含義
咱們看到了表面的樣子,可是這兩個內部變量到底幹嗎的?
對於defaultUncaughtExceptionHandler,表示的是應用程序默認的,應用程序默認的,也就是整個程序使用的,能夠看獲得,對於他的getter和setter以及自身,都是static修飾的
對於uncaughtExceptionHandler,屬於實例方法,也就是說每一個線程能夠擁有一個
簡言之:每一個線程均可以有一個uncaughtExceptionHandler,整個應用能夠有一個defaultUncaughtExceptionHandler
全局和個體的關係,就如同咱們平時見到的其餘概念同樣,若是單獨設置了,那麼就使用本身的,若是沒有設置就走全局的
既能夠單獨設置,又能夠全局設置(沒有設置的纔會走全局),既能夠保障靈活性,有可以對於那些沒設置的提供統一配置,好比統一將異常信息寫入文件等,也有諸多應用場景與好處
異常處理器處理邏輯
當異常發生時,JVM會調用異常分發處理器,也就是藉助於getUncaughtExceptionHandler方法,獲取異常處理器,而後執行他的uncaughtException方法
第一個參數就是當前線程this,第二個參數就是異常對象
看註釋:JVM調用
因此關鍵點在於getUncaughtExceptionHandler返回什麼異常處理器,咱們再回過頭來看下源代碼
若是已經設置,那麼將會直接返回;
若是沒有設置,將會返回當前線程組(前面說了ThreadGroup實現了Thread.UncaughtExceptionHandler)
當調用ThreadGroup的uncaughtException方法時,如上圖下半部分
若是他的父線程組重寫了uncaughtException方法,那麼將會調用他的父線程組的方法,若是父親節點沒有重寫,爺爺節點重寫了將會調用爺爺的,以此類推
可是若是全部的祖先線程組都沒有重寫呢?很顯然,全部的方法代碼都是上面這樣子的(上圖下半部分),將會遞歸到頂級線程組,而後不知足parent,而後走到else,這中間什麼有意義的事情都沒有作
在else中,會首先獲取應用默認的異常處理器,若是仍舊是沒有設置
很差意思,直接轉到system.err了
代碼示例
從上面的示例能夠看得出來,儘管仍就出現了異常,咱們可以進行信息獲取與感知,不會直接宕掉了
若是先start,而後在設置異常處理器會發生什麼?
能夠看獲得,線程仍舊是直接宕掉,異常處理器無效,因此setUncaughtExceptionHandler方法必須在start方法前調用!
總結
在Thread中的run方法,不可以拋出異常,只能進行捕獲
- 對於已檢查異常,必須捕獲
- 對於未檢查異常,你也能夠進行try catch,可是代碼始終包裹在try中,真的好嗎?
- 還另外提供了異常處理器機制用於處理未檢查異常
有兩種異常處理器:
線程自身的處理器和全局的異常處理器
- 若是設置了異常處理器uncaughtExceptionHandler,那麼將會使用這個
- 若是沒設置,將會在祖先線程組中查找第一個重寫了uncaughtException的線程組,而後調用他的uncaughtException方法
- 若是都沒有重寫,那麼使用應用默認的全局異常處理器defaultUncaughtExceptionHandler
- 若是仍是沒有設置,直接標準錯誤打印信息
若是想要設置本身的異常處理器,能夠經過對應的setter方法進行設置,若是想要設置全局的能夠調用靜態方法進行設置
異常處理器Thread.UncaughtExceptionHandler是一個函數式接口,因此後續,你可使用Lambda表達式直接編寫,大大減小了工做量