關於java多線程中異常捕獲的理解

在java多線程程序中,全部線程都不容許拋出未捕獲的checked exception(好比sleep時的InterruptedException)也就是說各個線程須要本身把本身的checked exception處理掉java

這句話怎麼理解,最簡單的看下圖,也就是不能在Runnable的run方法上拋出異常,必須在裏面捕獲多線程

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

看下面的例子:spa

public class ExceptionTest {

    public static void main(String[] args) {
        
        try {
            new Thread(new ExceptionTask()).start();
        } catch (Exception e) {
            System.out.println("注意看我是否能打印。。。");
            e.printStackTrace();
        }
    }
    
}

class ExceptionTask implements Runnable {

    @Override
    public void run() {
        System.out.println("".substring(0, 10));
    }
    
}

打印結果線程

Exception in thread "Thread-0" java.lang.StringIndexOutOfBoundsException: String index out of range: 10
    at java.lang.String.substring(Unknown Source)
    at com.actuator.ExceptionTask.run(ExceptionTest.java:21)
    at java.lang.Thread.run(Unknown Source)

從運行結果中,咱們能夠看到的是,"Thread-0"線程裏的異常在main線程中沒有catch到設計

問題來了,咱們若是須要捕獲"Thread-0"線程的unchecked異常時該怎麼辦?Java SE5以後,咱們能夠經過Executor來解決這個問題。code

Thread.UncaughtExceptionHandler是java SE5中的新接口,它容許咱們在每個Thread對象上添加一個異常處理器。(UncaughtExceptionHandler)。Thread.UncaughtExceptionHandler.uncaughtException()方法會在線程因未捕獲的異常而面臨死亡時被調用對象

下面這個例子簡單的演示瞭如何使用UncaughtExceptionHandler。blog

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

public class ExceptionTest {

    public static void main(String[] args) {
        
        // 下面有兩種方式來執行線程
        
        // 第一種,非線程池寫法
        Thread t = new Thread(new ExceptionTask());
        t.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread t, Throwable e) {
                System.out.println("線程"+t.getName()+"捕獲到異常:"+e.getMessage());
            }
        });
        t.start();
        
        // 第二種,線程池寫法
        ExecutorService executorService = Executors.newCachedThreadPool(new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                Thread t = new Thread(r);
                t.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
                    @Override
                    public void uncaughtException(Thread t, Throwable e) {
                        System.out.println("線程"+t.getName()+"捕獲到異常:"+e.getMessage());
                    }
                });
                return t;
            }
        });
        executorService.execute(new ExceptionTask());
        
        
        
    }
    
}

class ExceptionTask implements Runnable {

    @Override
    public void run() {
        System.out.println("".substring(0, 10));
    }
    
}

兩個執行結果同樣接口

線程Thread-0捕獲到異常:String index out of range: 10
相關文章
相關標籤/搜索