捕獲異步線程異常的常用方式

聲明 捕獲異步線程異常的方式有很多,本文只介紹(並示例)幾種相對常用的方式。


捕獲異步線程異常的常用方式(結論)

開啓線程的方式 使用線程池的情況 捕獲異步線程異常的常用方式
Thread 不使用線程池 1. Thread.setDefaultUncaughtExceptionHandler設置默認的線程異常處理器。
2. Thread實例.setUncaughtExceptionHandler給當指定線程設置線程異常處理器。
Thread 使用線程池ExecutorService#execute 1. Thread.setDefaultUncaughtExceptionHandler設置默認的線程異常處理器。
2.自定義ThreadPoolExecutor, 重寫afterExecute方法,在afterExecute方法中感知異常。
Thread 使用線程池ExecutorService#submit 自定義ThreadPoolExecutor, 重寫afterExecute方法,在afterExecute方法中感知異常。
Runnable 不使用線程池 1. Thread.setDefaultUncaughtExceptionHandler設置默認的線程異常處理器。
2. Thread實例.setUncaughtExceptionHandler給當指定線程設置線程異常處理器。
Runnable 使用線程池ExecutorService#execute 1. Thread.setDefaultUncaughtExceptionHandler設置默認的線程異常處理器。
2. 自定義ThreadPoolExecutor, 重寫afterExecute方法,在afterExecute方法中感知異常。
Runnable 使用線程池ExecutorService#submit 自定義ThreadPoolExecutor, 重寫afterExecute方法,在afterExecute方法中感知異常。
Callable 不使用線程池 在使用Future#get()方法獲取Callable#call()的返回結果時, try-catch獲取異常
注:此方式,若不使用Future#get()獲取結果,那麼 異步線程的異常信息將會被吞掉。
Callable 使用線程池ExecutorService#submit 自定義ThreadPoolExecutor, 重寫afterExecute方法,在afterExecute方法中感知異常。

捕獲異步線程異常的常用方式(示例說明)

提示 完整測試項目可見文末鏈接。
準備工作

  • 一個Thread
    在這裏插入圖片描述
  • 一個Runnable
    在這裏插入圖片描述
  • 一個Callable
    在這裏插入圖片描述
  • 一個UncaughtExceptionHandler
    在這裏插入圖片描述
  • 一個ThreadPoolExecutor
    在這裏插入圖片描述

Thread不使用線程池

  • 方式一:Thread.setDefaultUncaughtExceptionHandler
    /**
     * [不使用線程池]方式一: Thread.setDefaultUncaughtExceptionHandler 設置默認的線程異常處理器
     */
    private static void testThread1() {
        Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
        MyThread myThread = new MyThread();
        myThread.start();
    }
    
  • 方式二:Thread實例.setUncaughtExceptionHandler
    /**
     * [不使用線程池]方式二: Thread實例.setUncaughtExceptionHandler 給當指定線程設置線程異常處理器
     */
    private static void testThread2() {
        MyThread myThread = new MyThread();
        myThread.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
        myThread.start();
    }
    

Thread使用線程池ExecutorService#execute

  • 方式一:Thread.setDefaultUncaughtExceptionHandler
    /**
     * [使用線程池execute]方式一: Thread.setDefaultUncaughtExceptionHandler 設置默認的線程異常處理器
     */
    private static void testThread3() {
        Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        MyThread myThread = new MyThread();
        executorService.execute(myThread);
    }
    
  • 方式二:自定義ThreadPoolExecutor, 重寫afterExecute方法
    /**
     * [使用線程池execute]方式二: 自定義ThreadPoolExecutor, 重寫afterExecute方法,在afterExecute方法中感知異常
     */
    private static void testThread4() {
        ExecutorService executorService = new MyThreadPoolExecutor(5,
                50, 3, TimeUnit.SECONDS, new LinkedBlockingQueue<>(20),
                Thread::new, new ThreadPoolExecutor.AbortPolicy());
        MyThread myThread = new MyThread();
        executorService.execute(myThread);
    }
    

Thread使用線程池ExecutorService#submit

  • 方式:自定義ThreadPoolExecutor, 重寫afterExecute方法
    /**
     * [使用線程池submit]方式一: 自定義ThreadPoolExecutor, 重寫afterExecute方法,在afterExecute方法中感知異常
     */
    private static void testThread5() {
        ExecutorService executorService = new MyThreadPoolExecutor(5,
                50, 3, TimeUnit.SECONDS, new LinkedBlockingQueue<>(20),
                Thread::new, new ThreadPoolExecutor.AbortPolicy());
        MyThread myThread = new MyThread();
        executorService.submit(myThread);
    }
    

Runnable不使用線程池

  • 方式一:Thread.setDefaultUncaughtExceptionHandler
    /**
     * [不使用線程池]方式一: Thread.setDefaultUncaughtExceptionHandler 設置默認的線程異常處理器
     */
    private static void testRunnable1() {
        Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
        MyRunnable myRunnable = new MyRunnable();
        new Thread(myRunnable).start();
    }
    
  • 方式二:Thread實例.setUncaughtExceptionHandler
    /**
     * [不使用線程池]方式二: Thread實例.setUncaughtExceptionHandler 給當指定線程設置線程異常處理器
     */
    private static void testRunnable2() {
        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable);
        thread.setUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
        thread.start();
    }
    

Runnable使用線程池ExecutorService#execute

  • 方式一:Thread.setDefaultUncaughtExceptionHandler
    /**
     * [使用線程池execute]方式一: Thread.setDefaultUncaughtExceptionHandler 設置默認的線程異常處理器
     */
    private static void testRunnable3() {
        Thread.setDefaultUncaughtExceptionHandler(new MyUncaughtExceptionHandler());
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        MyRunnable myRunnable = new MyRunnable();
        executorService.execute(myRunnable);
    }
    
  • 方式二:自定義ThreadPoolExecutor, 重寫afterExecute方法
    /**
     * [使用線程池execute]方式二: 自定義ThreadPoolExecutor, 重寫afterExecute方法,在afterExecute方法中感知異常
     */
    private static void testRunnable4() {
        ExecutorService executorService = new MyThreadPoolExecutor(5,
                50, 3, TimeUnit.SECONDS, new LinkedBlockingQueue<>(20),
                Thread::new, new ThreadPoolExecutor.AbortPolicy());
        MyRunnable myRunnable = new MyRunnable();
        executorService.execute(myRunnable);
    }
    

Runnable使用線程池ExecutorService#submit

  • 方式:自定義ThreadPoolExecutor, 重寫afterExecute方法
    	/**
    	 * [使用線程池submit]方式一: 自定義ThreadPoolExecutor, 重寫afterExecute方法,在afterExecute方法中感知異常
    	 */
    	private static void testRunnable5() {
    	    ExecutorService executorService = new MyThreadPoolExecutor(5,
    	            50, 3, TimeUnit.SECONDS, new LinkedBlockingQueue<>(20),
    	            Thread::new, new ThreadPoolExecutor.AbortPolicy());
    	    MyRunnable myRunnable = new MyRunnable();
    	    executorService.submit(myRunnable);
    	}
    

Callable不使用線程池

  • 方式:在使用Future#get()方法獲取Callable#call()的返回結果時, try-catch獲取異常
    /**
     * [不使用線程池]: 在使用Future#get()方法獲取Callable#call()的返回結果時, try-catch獲取異常
     *
     * 注: 此方式, 若不使用Future#get()獲取結果,那麼 異步線程的異常信息將會被吞掉
     */
    private static void testCallable1() throws InterruptedException {
        MyCallable myCallable = new MyCallable();
        FutureTask<Object> futureTask = new FutureTask<> (myCallable);
        Thread thread = new Thread(futureTask);
        thread.start();
        try {
            // 在嘗試獲取結果時,捕獲異常
            Object o = futureTask.get();
        } catch (ExecutionException e) {
            Throwable cause = e.getCause();
            log.error(" callable-thread occur exception", cause);
        }
    }
    

Callable使用線程池ExecutorService#submit

  • 方式:自定義ThreadPoolExecutor, 重寫afterExecute方法
    /**
     * [使用線程池submit]: 自定義ThreadPoolExecutor, 重寫afterExecute方法,在afterExecute方法中感知異常
     */
    private static void testCallable2() {
        ExecutorService executorService = new MyThreadPoolExecutor(5,
                50, 3, TimeUnit.SECONDS, new LinkedBlockingQueue<>(20),
                Thread::new, new ThreadPoolExecutor.AbortPolicy());
        MyCallable myCallable = new MyCallable();
        executorService.submit(myCallable);
    }
    

個人推薦

  • 如果異步線程不需要返回值的話,個人推薦創建線程用Runnable執行線程用ExecutorService#execute異常處理用Thread.setDefaultUncaughtExceptionHandler
  • 如果異步線程需要返回值的話,個人推薦創建線程用Callable執行線程用ExecutorService#submit異常處理用主動編碼對Future#get進行try-catch的方式

^_^ 如有不當之處,歡迎指正

^_^ 測試代碼託管鏈接
         https://github.com/JustryDeng…CatchSyncThreadException…

^_^ 本文已經被收錄進《程序員成長筆記(三)》,筆者JustryDeng

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章