捕获线程中的异常
為什么80%的碼農都做不了架構師?>>> ??
由于線程的本質特性,使得你不能捕獲從線程中逃逸的異常。一旦異常逃出任務的run()方法它就會向外傳播到控制臺,除非你采取特殊的步驟捕獲這種錯誤的異常。在Java SE5之前,你可以使用線程組來捕捉這種異常,但是有了Java SE5,就可以用Executor來解決這個問題了。
下面的任務總是會拋出一個異常,該異常會傳播到其run()方法的外部,并且main()展示了當你運行它時所發生的事情:
import?java.util.concurrent.ExecutorService; import?java.util.concurrent.Executors;public?class?ExceptionThread?implements?Runnable?{public?void?run()?{throw?new?RuntimeException();}public?static?void?main(String[]?args)?{ExecutorService?service?=?Executors.newCachedThreadPool();service.execute(new?ExceptionThread());} }輸出如下:
Exception?in?thread?"pool-1-thread-1"?java.lang.RuntimeExceptionat?com.abc.thread.ExceptionThread.run(ExceptionThread.java:6)at?java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)at?java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)at?java.lang.Thread.run(Thread.java:745)將main的主體放在try-catch語句塊中也是沒有作用的:
import?java.util.concurrent.ExecutorService; import?java.util.concurrent.Executors;public?class?ExceptionThread?implements?Runnable?{public?void?run()?{throw?new?RuntimeException();}public?static?void?main(String[]?args)?{try?{ExecutorService?service?=?Executors.newCachedThreadPool();service.execute(new?ExceptionThread());}?catch?(RuntimeException?e)?{System.out.println("Catched?Runtime?Exception.");}} }這將產生于前面示例相同的結果:未捕獲的異常。
為了解決這個問題,我們要修改Executor產生線程的方式。Thread.UncaughtExceptionHandler是Java SE5中的新接口,它允許你在每個Thread對象上都附著一個異常處理器。Thread.UncaughtExceptionHandler.uncaughtException()會在線程因未捕獲的異常而臨近死亡時被調用。為了使用它,我們創建了一個新類型的ThreadFactory,它將在每個新創建的Thread對象上附著一個Thread.UncaughtExceptionHandler。
import?java.util.concurrent.ExecutorService; import?java.util.concurrent.Executors; import?java.util.concurrent.ThreadFactory;public?class?ExceptionThread2?implements?Runnable?{public?void?run()?{throw?new?RuntimeException("NullPointer");}public?static?void?main(String[]?args)?{ThreadFactory?tFactory?=?new?MyThreadFactory();ExecutorService?service?=?Executors.newCachedThreadPool(tFactory);Runnable?task?=?new?ExceptionThread2();service.execute(task);} }class?MyUncaughtExceptionHandler?implements?Thread.UncaughtExceptionHandler?{//?處理從線程里拋出來的異常。public?void?uncaughtException(Thread?t,?Throwable?e)?{System.out.println("Catched?Throwable:?"?+?e.getClass().getSimpleName()?+?",?"?+?e.getMessage());} }class?MyThreadFactory?implements?ThreadFactory?{//?重新組織創建線程的方式public?Thread?newThread(Runnable?r)?{Thread?t?=?new?Thread(r);//?為每一個線程都綁定一個異常處理器。t.setUncaughtExceptionHandler(new?MyUncaughtExceptionHandler());System.out.println("Thread["?+?t.getName()?+?"]?created.");return?t;} }執行的結果如下:
可以看到,線程池中有2個線程,當一個線程發生異常時,該異常被捕捉了。
上面的示例使得你可以按照具體情況(在newThread()方法中使用if, case等語句)為每個線程逐個的設置處理器。如果你知道將要在代碼中處處使用相同的異常處理器,那么更簡單的方式是在Thread類中設置一個靜態域,并將這個處理器設置為默認的處理器即可:
import?java.util.concurrent.ExecutorService; import?java.util.concurrent.Executors;public?class?SettingDefaultHandler?{public?static?void?main(String[]?args)?{//?為線程設置默認的異常處理器。Thread.setDefaultUncaughtExceptionHandler(new?MyUncaughtExceptionHandler());ExecutorService?exec?=?Executors.newCachedThreadPool();exec.execute(new?ExceptionThread2());} }這個處理器只有在不存在線程專有的未捕獲異常處理器的情況下才會被調用。系統會檢查線程專有版本,如果沒有發現,則檢查線程組是否有專有的uncaughtException()方法,如果也沒有,才會調用defaultUncaughtExceptionHandler。
轉載于:https://my.oschina.net/itblog/blog/502479
總結
- 上一篇: C# 之 用NPOI类库操作Excel
- 下一篇: jquery中的attr()和prop(