????Java虛擬機里面的異常使用Throwable或其子類的實例來表示,拋異常的本質實際上是程序控制權的一種即時的、非局部(Nonlocal)的轉換——從異常拋出的地方轉換至處理異常的地方。
絕大多數的異常的產生都是由于當前線程執行的某個操作所導致的,這種可以稱為是同步的異常。與之相對的,異步異常是指在程序的其他任意地方進行的動作而導致的異常。Java虛擬機中異常的出現總是由下面三種原因之一導致的:
1.虛擬機同步檢測到程序發生了非正常的執行情況,這時異常將會緊接著在發生非正常執行情況的字節碼指令之后拋出。例如:
字節碼指令所蘊含的操作違反了Java語言的語義,如訪問一個超出數組邊界范圍的元素。
類在加載或者鏈接時出現錯誤。
使用某些資源的時候產生資源限制,例如使用了太多的內存。
2.athrow字節碼指令被執行。
3.由于以下原因,導致了異步異常的出現:
調用了Thread或者ThreadGroup的stop方法。
Java虛擬機實現的內部程序錯誤。
????當某條線程調用了stop方法時,將會影響到其他的線程,或者在線程組中的所有線程。這時候其他線程中出現的異常就是異步異常,因為這些異常可能出現在程序執行過程的任何位置。虛擬機的內部異常也被認為是一種異步異常
????《Java虛擬機規范》允許在異步異常被拋出時額外執行一小段有限的代碼,允許代碼優化器在不違反Java語言語義的前提下檢測并把這些異常在可處理它們的地方拋出①。
????拋出異常的動作在Java虛擬機之中是一種被精確定義的程序控制權轉移過程,當異常拋出、程序控制權發生轉移的那一刻,所有在異常拋出的位置之前的字節碼指令所產生的影響②都應當是可以被觀察到的,而在異常拋出的位置之后的字節碼指令,則應當是沒有被執行過的。如果虛擬機執行的代碼是被優化后的代碼③,有一些在異常出現位置之后的代碼可能已經被執行了,那這些優化過的代碼必須保證被它們提前執行所產生的影響對用戶程序來說都是不可見的。
????由Java虛擬機執行的每一個方法都會配有零至多個異常處理器(Exception Handlers),異常處理器描述了其在方法代碼中的有效作用范圍(通過字節碼偏移量范圍來描述)、能處理的異常類型以及處理異常的代碼所在的位置。要判斷某個異常處理器是否可以處理某個具體的異常,需要同時檢查異常出現的位置是否在異常處理的有效作用范圍內并且出現的異常是否異常處理器聲明可以處理的異常類型或其子類型兩個條件。當有異常被拋出時,Java虛擬機搜索當前方法的包含的各個異常處理器,如果能找到可以處理該異常的異常處理器,則將代碼控制權轉向到異常處理器中描述的處理異常的分支之中。
????搜索異常處理器時的搜索順序是很關鍵的,在Class文件里面,每個方法的異常處理器都存儲在一個表中。在運行時,當有異常出現之后,Java虛擬機就按照Class文件中的異常處理器表描述異常處理器的先后順序,從前至后進行搜索。
????需要注意,Java虛擬機本身不會對方法的對異常處理器表做排序或者其他方式的強制處理,所以Java語言中對異常處理的語義,實際上是通過編譯器適當安排異常處理器在表中的順序來協助完成的。在Class文件中定義了明確的異常處理器查找順序,才能保證無論Class文件是通過何種途徑產生的,Java虛擬機執行時都能有一致的行為表現。
轉載于:https://blog.51cto.com/zangyanan/1855720