捕获异步线程异常的常用方式

声明 捕获异步线程异常的方式有很多,本文只介绍(并示例)几种相对常用的方式。


捕获异步线程异常的常用方式(结论)

开启线程的方式 使用线程池的情况 捕获异步线程异常的常用方式
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

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