多線程異常捕獲

1.多線程經常使用方式

  • 建立Thread
  • 使用線程池

2.實現接口

  • Runnable,無返回值
  • Callable,可有返回值

3.異常捕獲

線程運行過程當中發生的異常,沒法經過try catch方式,在外層進行捕獲,例如java

try {
          new Thread(new Runnable() {
                @Override
                public void run() {
                    int i = 1 / 0;
                }
            }).start();
        } catch (Exception e) {
            System.out.println("error");
        }

執行上面的代碼,你會發現,error永遠不會打印在你的控制檯或是log中,緣由爲什麼,沒去深究,不過我想大概是由於線程有本身獨立的棧區多線程

4.如何捕獲異常

  • 建立Thread方式 使用UncaughtExceptionHandler方式捕獲運行時異常
try {
    Thread thread = new Thread(new Runnable() {
        @Override
        public void run() {
            int i = 1 / 0;
        }
    });
    thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
        @Override
        public void uncaughtException(Thread t, Throwable e) {
            System.out.println("uncaughtException");
        }
    });
    thread.start();
} catch (Exception e) {
    System.out.println("error");
}
  • 使用線程池方式 一般咱們都會使用concurrent包中的一些工具類來建立使用線程池,Executors爲咱們提供了幾種線程池,可是底層實現其實都是使用ThreadPoolExecutor,ThreadPoolExecutor預留了方法afterExecute能夠讓咱們實現線程內異常的處理
private static ThreadPoolExecutor executorPool = new ThreadPoolExecutor(4, 20,
            0L, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<Runnable>(1),
            new SimpleThreadFactory("executor"),
            new CustomRejectedExecutionHandler()
    ) {
        @Override
        protected void afterExecute(Runnable r, Throwable t) {
            super.afterExecute(r, t);
            if (t == null && r instanceof Future<?>) {
                try {
                    Object result = ((Future<?>) r).get();
                } catch (CancellationException ce) {
                    t = ce;
                } catch (ExecutionException ee) {
                    t = ee.getCause();
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt(); // ignore/reset
                }
            }
            if (t != null) {
                System.out.println("t is :" + t);
                t.printStackTrace();
            }
        }
    };

這樣就能夠在異常發生時,能夠打印出異常信息,而不是被吃掉ide

5.被吃掉的緣由

咱們在sumbit任務到ThreadPool時,自動爲咱們包裝成了FutureTask,而FutureTask對象在執行時,是會把異常吃掉,直到咱們get FutureTask的執行結果時纔會把異常拋出。相關的代碼以下: 工具

相關文章
相關標籤/搜索