您好,登錄后才能下訂單哦!
使用JVM怎么處理未捕獲的異常?很多新手對(duì)此不是很清楚,為了幫助大家解決這個(gè)難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來學(xué)習(xí)下,希望你能有所收獲。
什么是未捕獲異常
未捕獲異常指的是我們?cè)诜椒w中沒有使用try-catch捕獲的異常,比如下面的例子
private static void testUncaughtException(String arg) { try { System.out.println(1 / arg.length()); } catch (ArithmeticException e) { e.printStackTrace(); } }
上面的代碼很有可能發(fā)生如下情況
如果方法參數(shù)arg傳遞null,會(huì)出現(xiàn)NullPointerException
如果參數(shù)arg傳遞內(nèi)容為空的字符串(“”),會(huì)出現(xiàn)ArithmeticException
對(duì)于上面的問題,我們不難發(fā)現(xiàn)
上面可能出現(xiàn)的NullPointerException和ArithmeticException都屬于Unchecked Exceptions
而ArithmeticException被我們?nèi)藶閠ry-catch捕獲了,它不符合本文對(duì)于未捕獲異常的定義
NullPointerException 由于我們沒有catch住,就變成了我們要聊的未捕獲異常
另外,未捕獲異常實(shí)際是Unchecked Exceptions的子集
UncaughtExceptionHandler 是什么
它是線程遇到未捕獲異常的一個(gè)處理者接口
它包含一個(gè)方法void uncaughtException(Thread t, Throwable e);
用來處理接收處理異常發(fā)生后的操作,比如收集崩潰信息并上報(bào)等
可以通過 實(shí)例方法 Thread.setUncaughtExceptionHandler
為某一個(gè)Thread實(shí)例設(shè)置未捕獲異常處理者
也可以通過 靜態(tài)方法 Thread.setDefaultUncaughtExceptionHandler
設(shè)置所有Thread實(shí)例的未捕獲異常處理者
ThreadGroup 是什么
ThreadGroup 是線程的集合
ThreadGroup 也可以包含子ThreadGroup
除了初始的ThreadGroup 之外,每個(gè)ThreadGroup都有一個(gè)父 ThreadGroup
ThreadGroup 自身實(shí)現(xiàn)了Thread.UncaughtExceptionHandler,用來相應(yīng)處理其內(nèi)部的線程和ThreadGroup發(fā)生未捕獲異常。
未捕獲異常處理者 設(shè)置指南
線程發(fā)生了未捕獲異常,JVM怎么處理
分發(fā)Throwable實(shí)例
當(dāng)線程A中出現(xiàn)了未捕獲異常時(shí),JVM會(huì)調(diào)用線程A的dispatchUncaughtException(Throwable)
方法
/** * 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); }
獲取未捕獲異常處理者
每個(gè)線程會(huì)有一個(gè)變量(uncaughtExceptionHandler)來保存未捕獲異常的處理者
在線程需要確定Throwable分發(fā)目標(biāo)的處理者時(shí),優(yōu)先獲取當(dāng)前線程中uncaughtExceptionHandler變量
如果出問題線程的uncaughtExceptionHandler為null(即沒有顯式設(shè)置異常處理者),則使用自己所在的ThreadGroup來作為未捕獲異常處理者。
/** * Returns the handler invoked when this thread abruptly terminates * due to an uncaught exception. If this thread has not had an * uncaught exception handler explicitly set then this thread's * <tt>ThreadGroup</tt> object is returned, unless this thread * has terminated, in which case <tt>null</tt> is returned. * @since 1.5 * @return the uncaught exception handler for this thread */ public UncaughtExceptionHandler getUncaughtExceptionHandler() { return uncaughtExceptionHandler != null ? uncaughtExceptionHandler : group; }
如果Throwable分發(fā)給ThreadGroup
ThreadGroup會(huì)嘗試轉(zhuǎn)給它的父ThreadGroup(如果存在的話)
如果上面沒有找到對(duì)應(yīng)的ThreadGroup,則嘗試獲取Thread.getDefaultUncaughtExceptionHandler()并分發(fā)
/** * Called by the Java Virtual Machine when a thread in this * thread group stops because of an uncaught exception, and the thread * does not have a specific {@link Thread.UncaughtExceptionHandler} * installed. * <p> * The <code>uncaughtException</code> method of * <code>ThreadGroup</code> does the following: * <ul> * <li>If this thread group has a parent thread group, the * <code>uncaughtException</code> method of that parent is called * with the same two arguments. * <li>Otherwise, this method checks to see if there is a * {@linkplain Thread#getDefaultUncaughtExceptionHandler default * uncaught exception handler} installed, and if so, its * <code>uncaughtException</code> method is called with the same * two arguments. * <li>Otherwise, this method determines if the <code>Throwable</code> * argument is an instance of {@link ThreadDeath}. If so, nothing * special is done. Otherwise, a message containing the * thread's name, as returned from the thread's {@link * Thread#getName getName} method, and a stack backtrace, * using the <code>Throwable</code>'s {@link * Throwable#printStackTrace printStackTrace} method, is * printed to the {@linkplain System#err standard error stream}. * </ul> * <p> * Applications can override this method in subclasses of * <code>ThreadGroup</code> to provide alternative handling of * uncaught exceptions. * * @param t the thread that is about to exit. * @param e the uncaught exception. * @since JDK1.0 */ 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); } } }
將上面的處理流程做成圖的形式,就是下圖所示
注:上述圖片來自https://www.javamex.com/tutorials/exceptions/exceptions_uncaught_handler.shtml
Questions
初始的ThreadGroup是什么
上面提到了初始的ThreadGroup沒有父ThreadGroup,是主線程所在的ThreadGroup么?
這個(gè)問題,我們可以通過這樣一段代碼驗(yàn)證
private static void dumpThreadGroups() { ThreadGroup threadGroup = Thread.currentThread().getThreadGroup(); while(threadGroup != null) { System.out.println("dumpThreadGroups threadGroup=" + threadGroup.getName()); threadGroup = threadGroup.getParent(); } }
執(zhí)行該方法對(duì)應(yīng)的輸出是
dumpThreadGroups threadGroup=main
dumpThreadGroups threadGroup=system
因此我們可以發(fā)現(xiàn),初始的ThreadGroup是一個(gè)叫做system的ThreadGroup,而不是main ThreadGroup
setDefaultUncaughtExceptionHandler 設(shè)置的一定會(huì)被調(diào)用到么
這其實(shí)是一個(gè)很好的問題,答案是不一定會(huì)被調(diào)用,因?yàn)榭赡艽嬖谝韵碌那闆r
出問題的線程設(shè)置了對(duì)應(yīng)的UncaughtExcpetionHandler,優(yōu)先響應(yīng)分發(fā)到這個(gè)Handler
出問題的線程所在的ThreadGroup包括其祖先ThreadGroup 重寫了uncaughtException 也可能造成線程默認(rèn)的Handler無法被調(diào)用
出問題的線程重寫了dispatchUncaughtException 可能性較小
出問題的線程重寫了getUncaughtExceptionHandler 可能性較小
看完上述內(nèi)容是否對(duì)您有幫助呢?如果還想對(duì)相關(guān)知識(shí)有進(jìn)一步的了解或閱讀更多相關(guān)文章,請(qǐng)關(guān)注億速云行業(yè)資訊頻道,感謝您對(duì)億速云的支持。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。