声明: 捕获异步线程异常的方式有很多,本文只介绍(并示例)几种相对常用的方式。
捕获异步线程异常的常用方式(结论):
开启线程的方式 | 使用线程池的情况 | 捕获异步线程异常的常用方式 |
---|---|---|
Thread | 不使用线程池 | 1. Thread.setDefaultUncaughtExceptionHandler 设置默认的线程异常处理器。2. Thread实例.setUncaughtExceptionHandler 给当指定线程设置线程异常处理器。 |
Thread | 使用线程池ExecutorService#execute | 1. Thread.setDefaultUncaughtExceptionHandler 设置默认的线程异常处理器。2. 自定义ThreadPoolExecutor, 重写afterExecute方法 ,在afterExecute方法中感知异常。3. 自定义ThreadFactory , 重写newThread方法,给线程工厂生产出来的Thread实例设置UncaughtExceptionHandler 。 |
Thread | 使用线程池ExecutorService#submit | 自定义ThreadPoolExecutor, 重写afterExecute方法 ,在afterExecute方法中感知异常。 |
Runnable | 不使用线程池 | 1. Thread.setDefaultUncaughtExceptionHandler 设置默认的线程异常处理器。2. Thread实例.setUncaughtExceptionHandler 给当指定线程设置线程异常处理器。 |
Runnable | 使用线程池ExecutorService#execute | 1. Thread.setDefaultUncaughtExceptionHandler 设置默认的线程异常处理器。2. 自定义ThreadPoolExecutor, 重写afterExecute方法 ,在afterExecute方法中感知异常。3. 自定义ThreadFactory , 重写newThread方法,给线程工厂生产出来的Thread实例设置UncaughtExceptionHandler 。 |
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
- 一个自定义的ThreadFactory
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); }
- 方式三:自定义ThreadFactory, 给线程工厂生产出来的Thread实例设置UncaughtExceptionHandler
/** * [使用线程池execute]方式三: 自定义ThreadFactory, 重写newThread方法,给线程工厂生 * 产出来的Thread实例设置UncaughtExceptionHandler */ private static void testThread5() { ExecutorService executorService = new ThreadPoolExecutor(5, 50, 3, TimeUnit.SECONDS, new LinkedBlockingQueue<>(20), new MyThreadFactory(), new ThreadPoolExecutor.AbortPolicy()); MyThread myThread = new MyThread(); executorService.execute(myThread); }
Thread使用线程池ExecutorService#submit:
- 方式:自定义ThreadPoolExecutor, 重写afterExecute方法
/** * [使用线程池submit]方式一: 自定义ThreadPoolExecutor, 重写afterExecute方法,在afterExecute方法中感知异常 */ private static void testThread6() { 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); }
- 方式三:自定义ThreadFactory, 给线程工厂生产出来的Thread实例设置UncaughtExceptionHandler
/** * [使用线程池execute]方式三: 自定义ThreadFactory, 重写newThread方法,给线程工厂生 * 产出来的Thread实例设置UncaughtExceptionHandler */ private static void testRunnable5() { ExecutorService executorService = new ThreadPoolExecutor(5, 50, 3, TimeUnit.SECONDS, new LinkedBlockingQueue<>(20), new MyThreadFactory(), new ThreadPoolExecutor.AbortPolicy()); MyRunnable myRunnable = new MyRunnable(); executorService.execute(myRunnable); }
Runnable使用线程池ExecutorService#submit:
- 方式:自定义ThreadPoolExecutor, 重写afterExecute方法
/** * [使用线程池submit]方式一: 自定义ThreadPoolExecutor, 重写afterExecute方法,在afterExecute方法中感知异常 */ private static void testRunnable6() { 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); }
^_^ 如有不当之处,欢迎指正
^_^ 测试代码托管链接
https://github.com/JustryDeng…CatchSyncThreadException…
^_^ 本文已经被收录进《程序员成长笔记》 ,笔者JustryDeng