JAVA 線程中的異常捕獲

在java多線程程序中,全部線程都不容許拋出未捕獲的checked exception(好比sleep時的InterruptedException),也就是說各個線程須要本身把本身的checked exception處理掉。這一點是經過java.lang.Runnable.run()方法聲明(由於此方法聲明上沒有throw exception部分)進行了約束。可是線程依然有可能拋出unchecked exception(如運行時異常),當此類異常跑拋出時,線程就會終結,而對於主線程和其餘線程徹底不受影響,且徹底感知不到某個線程拋出的異常(也是說徹底沒法catch到這個異常)。JVM的這種設計源自於這樣一種理念:「線程是獨立執行的代碼片段,線程的問題應該由線程本身來解決,而不要委託到外部。」基於這樣的設計理念,在Java中,線程方法的異常(不管是checked仍是unchecked exception),都應該在線程代碼邊界以內(run方法內)進行try catch並處理掉.換句話說,咱們不能捕獲從線程中逃逸的異常。
看下面的例子:html

複製代碼
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExceptionThread implements Runnable {

    @Override
    public void run() {
        throw new RuntimeException("這個線程就幹了這麼一件事,拋出一個運行時異常");
    }
    
    public static void main(String[] args) {
        try {
            ExecutorService exec = Executors.newCachedThreadPool();
            exec.execute(new ExceptionThread());
            System.out.println("該幹嗎幹嗎去");
        } catch (RuntimeException e) {
            System.out.println("能不能捕獲到異常?");
        }
        
    }

}
複製代碼

運行結果:java

該幹嗎幹嗎去
Exception in thread "pool-1-thread-1" java.lang.RuntimeException: 這個線程就幹了這麼一件事,拋出一個運行時異常
    at ExceptionThread.run(ExceptionThread.java:8)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:619)

從運行結果中,咱們能夠看到的是,這個異常在main線程中沒有catch到,即多線程

  System.out.println("能不能捕獲到異常?");

   永遠不會執行到。ide

        問題來了,咱們若是須要捕獲其線程的unchecked異常時該怎麼辦?Java SE5以後,咱們能夠經過Executor來解決這個我問題。爲了解決這個問題,咱們須要修改Executor產生線程的方式。Thread.UncaughtExceptionHandler是java SE5中的新接口,它容許咱們在每個Thread對象上添加一個異常處理器。(UncaughtExceptionHandler)。Thread.UncaughtExceptionHandler.uncaughtException()方法會在線程因未捕獲的異常而面臨死亡時被調用。下面這個例子簡單的演示瞭如何使用UncaughtExceptionHandlerspa

public  class  ExceptionThread2 implements  Runnable {
 
     @Override
     public  void  run() {
         Thread t = Thread.currentThread();
         System.out.println( "run() by"  + t);
         System.out.println( "eh="  + t.getUncaughtExceptionHandler());
         throw  new  RuntimeException( "拋出運行時異常" );
     }
}

 

複製代碼
import java.lang.Thread.UncaughtExceptionHandler;

/**
 * 用於捕獲異常---捕獲的是uncheckedException
 * 
 * @author February30th
 * 
 */
public class MyUnchecckedExceptionhandler implements UncaughtExceptionHandler {

    @Override
    public void uncaughtException(Thread t, Throwable e) {
        System.out.println("捕獲到異常:" + e);
    }

}
複製代碼
複製代碼
import java.util.concurrent.ThreadFactory;

public class HandlerThreadFactory implements ThreadFactory {

    @Override
    public Thread newThread(Runnable r) {
        System.out.println("建立一個新的線程");
        Thread t = new Thread(r);
        t.setUncaughtExceptionHandler(new MyUnchecckedExceptionhandler());
        System.out.println("eh121 = " + t.getUncaughtExceptionHandler());
        return t;
    }

}
複製代碼
複製代碼
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


public class ThreadExceptionTest {

    /**
     * @param args
     */
    public static void main(String[] args) {
        //下面有3中方式來執行線程。
        //第1種按照普通的方式。這是能捕獲到異常
        Thread t = new Thread(new ExceptionThread2());
        t.setUncaughtExceptionHandler(new MyUnchecckedExceptionhandler());
        t.start();
        //第2種按照現成池,直接按照thread方式,此時不能捕獲到異常,爲何呢?由於在下面代碼中建立了一個線程,且設置了異常處理器,
        //可是呢,在咱們線程池中會重設置新的Thread對象,而這個Thread對象沒有設置任何異常處理器,換句話說,咱們在線程池外對線程作的
        //任何操做都是沒有用的
        ExecutorService exec1 = Executors.newCachedThreadPool();
        Runnable runnable = new ExceptionThread2();
        Thread t1 = new Thread(runnable);
        t1.setUncaughtExceptionHandler(new MyUnchecckedExceptionhandler());
        exec1.execute(runnable);
        
        //第3種狀況同樣的,也是走的線程池,可是呢是經過ThreadFactory方式,在ThreadFactory中會對線程作一些控制,能夠設置異常處理器
        //此時是能夠捕獲異常的。
        ExecutorService exec = Executors.newCachedThreadPool(new HandlerThreadFactory());
        exec.execute(new ExceptionThread2());
        
    }

}
複製代碼

運行結果線程

建立一個新的線程
eh121 = MyUnchecckedExceptionhandler@1b8e059
run() byThread[Thread-0,5,main]
eh=MyUnchecckedExceptionhandler@1b8e059
捕獲到異常:java.lang.RuntimeException: 拋出運行時異常

從上述的運行結果中能夠看到,未捕獲的異常是經過uncaughtException來捕獲的。設計

按照上述的實例,咱們能夠按照具體的狀況,逐個地設置處理器。可是若是咱們知道將要在代碼的全部地方都是用相同的異常處理器,那麼更簡單的方式是在Thread類中設置一個靜態域,並將這個處理器設置爲默認的未捕獲異常處理器。看下面的例子:code

Thread.setDefaultUncaughtExceptionHandler(new MyUnchecckedExceptionhandler());
        ExecutorService exec = Executors.newCachedThreadPool(new HandlerThreadFactory());
        exec.execute(new ExceptionThread2());

這個默認的處理器只有在線程不存在非默認的異常處理器時纔會調用。 在運行時,系統會檢查線程是否有屬於本身的異常處理器,若是發現沒有,就去檢查相應的線程組是否有專有的異常處理器,若是發現也沒有,再調用默認的異常處理器。htm

摘自:http://www.cnblogs.com/chenfei0801/archive/2013/04/23/3039286.html對象

相關文章
相關標籤/搜索