1. 程式人生 > >在多執行緒中捕獲並處理RuntimeException

在多執行緒中捕獲並處理RuntimeException

在多執行緒的機制下,我們不能跨越執行緒在主執行緒中捕獲其他執行緒的異常。

對於非執行時異常,線上程很多很複雜的時候,為每個執行緒都寫一份異常處理程式也很難過。對於執行時異常,如果我們不能採取一些有用的措施,那麼異常會被丟擲到控制檯上。

比如下面的例子:

package AllThread;

/**
 * 
 * @author QuinnNorris
 * 
 *         捕獲異常
 */
public class ExceptionThread {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
Thread th = new Thread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub throw new RuntimeException(); } }); th.start(); } }

這是一段簡單的程式碼,它會丟擲一個執行時異常:

Exception in thread “Thread-0” java.lang.RuntimeException
at AllThread.ExceptionThread$1.run(ExceptionThread.java:15)
at java.lang.Thread.run(Thread.java:745)

我們可以看出, 由於沒有去設計捕獲異常,它被直接輸出到控制檯上。對於這種情況,為main函式加上try-catch語句是沒有用的。

為了增加對異常處理的手段,在JAVA SE5中引入了使用Executor的一種解決方法。

package AllThread;

import java.lang.Thread.UncaughtExceptionHandler;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;

/**
 * 
 * @author
QuinnNorris * * 使用UncaughtExceptionHandler捕獲異常 */
public class UEHThread { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub ExecutorService es = Executors.newCachedThreadPool(new ThreadFactory() { @Override public Thread newThread(Runnable r) { // TODO Auto-generated method stub Thread th = new Thread(r); th.setUncaughtExceptionHandler(new UncaughtExceptionHandler() { @Override public void uncaughtException(Thread t, Throwable e) { // TODO Auto-generated method stub System.out.println("catch it " + e); } }); return th; } }); es.execute(new Runnable() { @Override public void run() { // TODO Auto-generated method stub throw new RuntimeException(); } }); } }

因為我比較懶全部用內部類來表示,所以這段程式可能略有些難懂。

  1. 首先我們建立了一個執行緒池,然後為這個建立執行緒池的靜態方法賦予一個引數。這個引數是一個ThreadFactory類,這個類是用來描述線上程池中的執行緒具有的共性的。
  2. ThreadFactory有一個方法需要我們覆蓋就是newThread方法,這個方法的引數是我們要處理的Runnable任務,也就是我們要加入到執行緒池中的Runnable任務。
  3. 我們在這個方法中用一個th物件包含r物件,然後設定th物件的UncaughtExceptionHandler屬性。
  4. 這個setUncaughtExceptionHandler方法的引數是一個UncaughtExceptionHandler物件,這裡我們第二次用內部類。
  5. UncaughtExceptionHandler類的唯一一個方法是uncaughtException。這個方法用來表示對執行緒未檢查異常的處理方式,我們讓他在控制檯輸出一句話。到這裡我們對執行緒池的部署就完成了。
  6. 然後我們在這個執行緒池中新增一個Runnable任務,這個任務會丟擲一個未檢查異常。

現在我們執行程式,控制檯輸出:

catch it java.lang.RuntimeException

到此,對於執行緒run方法中的未檢查異常的處理就結束了。需要注意的是,我們向執行緒池中新增執行緒的方法要呼叫execute方法而不要使用submit方法,submit方法會把異常吞掉。從而控制檯將會什麼都不輸出。