異常處理器處理邏輯深入解析,本文對異常處理器進行了深入的剖析,本文能夠讓你對異常處理邏輯有一個清晰的認知 ...
在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
- 如果還是沒有設置,直接標準錯誤列印信息